Andreas said:
The only reason this doesn't work as they think, is because assignment
is always on the "pointer" and never on the whole Object.
Right, because the pointer (or null) is what val *is*. That is the
critical point here. The parameter is a reference, not an object. In
order to view this as pass-by-reference, you'd have to look at the
parameter itself as an object; a perspective that's generally in the
ballpark of what's going on, but is ultimately an inadequate model for
understanding the language.
Given a C-style pointer, one can (in C) either change the pointer, or
the pointed-to Object using assignment:
int i=42,j=84,*p=&i; // p is a pointer to i *p = 43; // now "i"
contains 43 (java has no pendant for that) p = &j; // "i" is not
touched, but p points to j now.
Indeed, because p is the pointer, while *p is the object pointed to.
Therefore, when p occurs on the left of an assignment, the pointer is
assigned. When *p does, the object is assigned. It's worth noting now
that C, like Java, has no pass by reference semantics. It is another
language that is entirely pass by value.
It isn't really necessary to resort to parameter passing to see the
difference.
No, it's certainly not necessary. But one you've got down the kinds of
values that a variable may have (primitive or reference), describing
parameter passing incorrectly, in such a way as to imply that variables
contain objects, then muddies the waters again.
By the (at least as "very") definition of "reference" alone, one might
expect different behaviour of Java already. No matter if it is passed or
not. Java doesn't really have "references" the way C++ has.
I'm not sure what C++ has to do with this.
There really isn't a widely used definition of a reference. The word is
used differently by different languages, and it's best to just adopt the
definition from the language in question. C++ means one thing; Java
another; CAML yet another. On the other hand, pass-by-reference is a
concept with a well-understood definition. Namely: the lvalue of the
formal parameter is the same as the lvalue of the actual parameter.
The confusion comes from talking about "references" in Java in the first
place, not from how something is passed to methods.
I don't agree with this. It works perfectly well to talk about
references in Java, and acknowledge that they are passed by value.
[ example of a mutable Object that get's passed down
into a function and modified there
Actually, that's not what happened at all. The function modified global
state (a static field of the class). I'm afraid you missed the point of
the example. I would be shocked if you are willing to call it pass by
reference. And yet it's ultimately the same thing that's going on when
you modify object state via references passed as parameters.
Btw., even in C++, which I think we agree does support both by-value and
by-ref passing of objects, really passes on only "addresses by value"
for that. Where is the difference? The difference is in the semantics
of assignment.
You are confusing the implementation with the language semantics. When
you pass something by reference in C++, the lvalue of the formal
parameter is the same as the lvalue of the actual parameter. In other
words, the formal parameter is just another name for the same object. So
when you assign to the formal parameter, you are assigning to that
object. That is the only thing that C++ tells you, so it's the only
thing you know. Anything else is speculating about the implementation
details of the compiler.
If we want to engage in such speculation: one possible implementation
(the one likely used for calls between separately compiled modules) is
that the compiler translates this into pushing a memory address onto the
stack. Another implementation technique is to arrange the stack such
that in all calls to a function, the object passed by reference is at a
fixed offset from the end of the caller's stack frame and then accessing
it directly where it sits there. Yet another, useful for small objects
and primitives (which are objects in C++ parlance) in inlined functions,
is to arrange so that the object is allocated to a register rather than
memory in the calling procedure, and leaving that register allocated for
that purpose across the procedure call so that there is no memory address
at all.
So long as the implementation is faithful to the semantic model of what's
going on, it is acceptable. The language semantics don't say that a
memory address is passed. There is nothing in the C++ language
specification about inserting pointer dereference operators
automatically, or anything like that. The spec says that the formal
parameter name inside the function denotes the same object as the actual
parameter in the calling context. It's the poorer books on C++ that
insist on describing behavior in terms of implementation.