Strings pretend to be immutable value objects, but they still have object identity, which doesn't really make sense as far as I can tell.
It still seems to me that the only good definition of an object variable's "value" in Java is its pointer.
Strings pretend to be immutable value objects, but they still have object identity, which doesn't really make sense as far as I can tell.
It still seems to me that the only good definition of an object variable's "value" in Java is its pointer.
Yeah. Java doesn't have proper value objects, there's these vestigal referencey effects everywhere, probably because of the language being designed for much more memory-constrained environments than those where it's actually used today. Still, most of the time you can just ignore that, remember a few simple rules like "always use .equals rather than ==" and you're good.
> It still seems to me that the only good definition of an object variable's "value" in Java is its pointer.
Good for technical pedantry maybe. Good for working programming, no - 99.9% of the time when you're talking about the "value" (not in terms of function-passing semantics, just generally) you want to talk about "foo", not about "an object reference to address 54fc892d".
> Good for technical pedantry maybe. Good for working programming, no - 99.9% of the time when you're talking about the "value" (not in terms of function-passing semantics, just generally) you want to talk about "foo", not about "an object reference to address 54fc892d".
This is almost exactly the same as pointers in just about every language that has them, though. You pass pointers around, copy them, and dereference them (which includes struct member access and array indexing), and that's about it. C is a little different because it somewhat conflates arrays with pointers to arrays, but that's hardly reason to decide that pointers are totally different. In C, you have a variable 'foo' whose type is 'T *' that when cast to an int happens to equal 0x54fc892d. The only abstraction mechanism you're asking for is the ability to store pointers in variables, it's nothing to do with their type. They're handles on objects, they're called pointers because they're values that 'point' to another value somewhere else, they're exactly what Java object variables are.
The difference is that in C you can talk about x being a char^^ value "pointer to address 54fc892d" because you can also talk about ^x being a char^ value "foo". In Java there is no ^x, so the only thing you can talk about when you want to talk about "foo" is "the value of x", and you want to talk about "foo" far more often than you want to talk about "pointer to address 54fc892d".
As an aside, C's conflation of arrays and pointers was done because they're very closely related, and you can get very similar results to a C pointer-to-pointer by wrapping an object in a one-element array. In C, ^x is equivalent to x[0], and Java doesn't have ^x, so you can just use x[0].
More generally, though, a C programmer is virtually never thinking of 'the address 54fc892d': unless they're doing really low-level stuff, they won't think of it like that any more than a Java programmer, even using pointers all day, just like the Java programmer is; that's what I don't get about your point. The C programmer will think of ^x (or alternatively x[0]) as a handle on the string "foo", the same way a good Java programmer would. Some programmers (Java or otherwise) might confuse a handle on "foo" with "foo" itself, but they'll be bitten by that when they try to write a swap function or mutate a string literal or whatever.
Java's reference types are restricted pointers that you can only dereference using . or array indexing, you can't use array indexing on any arbitrary reference (it has to be of the right type, but C pointers were already strongly typed), you can only do arithmetic on them via indexing, and you're not allowed to refer to the non-pointer type. None of those differences make them not pointers, to me.
No, I'm not talking about that at all (I guess I should've used an int rather than a string as an example, but we'd started with ints). I'm talking about the difference between char^ and char^^.
> a C programmer is virtually never thinking of 'the address 54fc892d': unless they're doing really low-level stuff, they won't think of it like that any more than a Java programmer, even using pointers all day, just like the Java programmer is; that's what I don't get about your point.
The C programmer might think of &x as a handle to x rather than a specific memory address, sure, but they can tell there's a difference between &x and x. The Java programmer doesn't have that distinction to work with.
> Java's reference types are restricted pointers that you can only dereference using . or array indexing, you can't use array indexing on any arbitrary reference (it has to be of the right type, but C pointers were already strongly typed), you can only do arithmetic on them via indexing, and you're not allowed to refer to the non-pointer type. None of those differences make them not pointers, to me.
I would say: a pointer has to point to something. Java doesn't have those because you can't get talk about "the thing the pointer points to" as a thing distinct from the pointer itself.
You get at the thing being pointed to by dereferencing the pointer. When you copy around handles to it, you can tell that you're only passing around handles, because if the object is mutable, then changes made from one handle show up in others, but your swap function still won't work. All you can do with the handle is pass it around, copy it, compare it to another handle with == or !=, dereference it, and add an index to it before dereferencing it. Dereferencing is specific to pointers, but for all the other things, they behave just like every over Java primitive does.
The effect of object variables just being pointers comes up in a lot of places, like "why doesn't my swap function work", using "==" to compare objects, initialising multiple variables to the same instance when you expected copy semantics, etc. These aren't rare things, and they're not difficult to think of. The fact that they're just pointers is the clearest explanation for all of that, and it by itself works for all of that.
Which you can't do in Java! There's no * operator.
Thinking in terms of pointers does illuminate some of Java's behaviour, sure, but it's not a reasonable way to understand the language when it requires all these concepts from C/C++ that just aren't there in Java.
> Which you can't do in Java! There's no * operator.
. and array indexing dereference pointers in Java, just as -> and array indexing do in C. I've already mentioned this several times.
> all these concepts from C/C++ that just aren't there in Java.
The Java language spec disagrees with you (before you said that explanation was pedantic; now it's incorrect?). As well, C and C++ did not invent pointers; you're the one insisting that Java's pointers aren't pointers because they don't behave identically to C's, I was saying that the specific differences don't change the fact that they're both flavours of pointer. No one is claiming that Java is source-compatible with C.
And really, there's no alternative explanation. You can learn each special case individually if you want and let your brain connect the dots to form the notion of how to use a reference without having sat down and thought about it and unified the concept, but that seems like so much work to get around learning a pretty simple idea that fully explains all of it without any special cases.
Neither of them will give you "the thing that's pointed to". And . very deliberately looks like a direct accessor in C/C++, not the dereferencing accessor ->.
> As well, C and C++ did not invent pointers; you're the one insisting that Java's pointers aren't pointers because they don't behave identically to C's, I was saying that the specific differences don't change the fact that they're both flavours of pointer.
The essence of a pointer - right there in the name - is that it's a thing that points to another thing. If the thing language has doesn't point to another thing in the language, you can't call it a pointer IMO.
> And really, there's no alternative explanation. You can learn each special case individually if you want and let your brain connect the dots to form the notion of how to use a reference without having sat down and thought about it and unified the concept, but that seems like so much work to get around learning a pretty simple idea that fully explains all of it without any special cases.
Disagree. If you learn: objects are passed by reference, == is a nonsense historical wart that you never use (as are arrays and primitves), and the default implementations of equals()/hashCode()/toString() should never be used, then you get a consistent working language that's much simpler, without having to involve anything from outside the language.
It points to a tangible thing in the language, the object that you're operating on, that thing just isn't a first class value, so you can't store it in a variable or pass it to a function. If this reasoning means that Java doesn't have pointers, then C doesn't have functions or arrays, either.
> If you learn: objects are passed by reference
They're visibly not passed by reference, though, you forgot the extra rule that using '=' on a parameter is also broken and to be avoided (from the perspective of pass by reference). So your explanation has 7 additional special rules to learn, including leaving multiple very common elements of the language at "just don't touch that", and still assumes the learner knows what a reference is anyway; why not just use the language of the Java spec and describe the actual semantics as they're defined, instead of this awkward simplifcation that takes longer to explain and involves more concepts?
> without having to involve anything from outside the language.
You also keep repeating this point even after it's been explained to be false; what language are you referring to when you keep saying Java doesn't have these concepts? The Java language spec from Oracle says:
"4.3.1. Objects
"An object is a class instance or an array.
"The reference values (often just references) are pointers to these objects, and a special null reference, which refers to no object."
They are also a part of the visible semantics of the language, as has been explained over and over in this thread, and that way you get a simple, consistent language, and it's one that people actually use instead of a made-up, more complicated subset.
Saying C doesn't have functions would be more like saying Java doesn't have objects: rather I'd say that C doesn't have pointers to functions (but has various syntactic weirdnesses to allow a function to behave like a pointer in some contexts, since the rest of the language has a value/pointer distinction).
"C doesn't have arrays, only some syntax sugar over pointers" is a common view among working C programmers. It's not a completely accurate model of the details of the language, but it can lead to fewer mistakes than not believing it (e.g. a function declaration like "int foo(int bar[5])" is actively misleading, and this is the kind of mistake someone who believes "C has arrays" may make and someone who believes "C doesn't have arrays, only some syntax sugar over pointers" won't make).
> They're visibly not passed by reference, though, you forgot the extra rule that using '=' on a parameter is also broken and to be avoided (from the perspective of pass by reference).
Point, though I think linters and IDEs warn on that one anyway.
> your explanation has 7 additional special rules to learn
Not really - you're going to have to explain the importance of not calling .equals()/.hashCode()/.toString() on random Objects either way, and you don't have to teach any extra special rules to avoid ==, != or arrays or primitives - you just don't teach any of those things.
> including leaving multiple very common elements of the language at "just don't touch that"
Any introduction to Java is going to involve a very long list of "don't touch that" (corba, dates, ejb, finalizers, monitors, AWT...), it's the nature of a language with a backwards compatibility history.
> why not just use the language of the Java spec and describe the actual semantics as they're defined, instead of this awkward simplifcation that takes longer to explain and involves more concepts?
I don't think either of those things are true. You have a bunch of extra concepts: class instances, references, and arrays - and class instances are particularly difficult to explain since they're not values in the language.
Your point was that that state of being able to have pointers to non-first-class values was a paradox, and my point was that C manages just fine (you clearly take it as an axiom that C has pointers).
> this is the kind of mistake someone who believes "C has arrays" may make and someone who believes "C doesn't have arrays, only some syntax sugar over pointers" won't make).
Sure; what are the corresponding gotchas with believing that Java has reference types? The fact that misunderstanding something in different ways will still give you problems (just believing that arrays are pointers will give you new mistakes to make, too, like with linkage and modifying string literals) isn't a very good justification for not attempting to understand it properly.
> you're going to have to explain the importance of not calling .equals()/.hashCode()/.toString() on random Objects either way
It's an obvious implication of what the default implementations do, and how they work is trivial to understand and an obvious choice for the default implementations if you know the concepts. If you understand reference types, then no further explanation is needed.
> you don't have to teach any extra special rules to avoid ==, != or arrays or primitives - you just don't teach any of those things.
You started off talking about working Java programmers in the real world, so I thought that's what we were discussing. Real-world Java programmers will see those things; you can't even write a main function without declaring an array. What about null? You can't get away with just leaving these things out, you do have to explain them as traps.
> I don't think either of those things are true. You have a bunch of extra concepts: class instances, references, and arrays
Those things you "removed" are in Java, though. Your advice was to treat them as black magic, not to actually modify the language (working programmers will see them). Knowing what features to avoid and be careful with when you can't avoid them (and presumably how to be careful with them) are things you have to learn and carry around in your head. And, as I pointed out, your version still requires people understand what references are (if you don't know what a reference is then what the hell is pass by reference passing by?). And wait then, so yours doesn't have references, primitives, arrays, or object instances? What values do you think are left in your theoretical subset?
And I disagreed with that by saying that C doesn't do that: it doesn't really have function pointers, it just allows function values to behave like pointers in some contexts.
> Real-world Java programmers will see those things; you can't even write a main function without declaring an array.
But you don't need to work with it as an array. You pass your argument array directly into an argument-parsing library and never look at it again, if your framework doesn't already do your main() for you.
> What about null?
What about it? It's a magic value that behaves like it's of every type, but throws NullPointerException when you call any methods on it. Try not to use it, try not to use libraries that use it. No pointers needed.
> And, as I pointed out, your version still requires people understand what references are (if you don't know what a reference is then what the hell is pass by reference passing by?).
You have to understand how Java passes parameters to functions (the receiver gets the same value). You don't have references as a first-class value.
> And wait then, so yours doesn't have references, primitives, arrays, or object instances? What values do you think are left in your theoretical subset?
Object values. String x = "foo" and String y = new String("foo") exist in my subset but are the same value (since I don't have object instances; x.equals(y) will be true which is the equality I care about). User-defined types exist as well, interfaces and polymorphism exist. You end up with a core language similar to, say, Python: everything is an object, objects are values rather than addresses, function parameters are passed by reference.