> For objects, the pass by value is the value of the reference to the object.
That's exactly what "pass by reference" means. According the SO definition, C is always pass by value: the value of the 'primitive' (int, long, char) or the value of the pointer (an address.) It pretty much applies to any language: ultimately you're passing a value from the caller to the callee. Whether that value is 'raw' (say, an int) or a pointer or reference is all in how you (or your compiler, or your runtime) interpret that value you received.
No, that's wrong. Pass-by-value with references as values, is not the same as pass-by-reference.
Plenty of people make the mistake of equating the two. They can get away with the misconception as long as they don't encounter a language like C# that features both reference types and optional pass-by-reference.
> According the SO definition, C is always pass by value
That's correct. C is always pass-by-value. You can get a similar effect to pass-by-reference, by passing a pointer.
> It pretty much applies to any language: ultimately you're passing a value from the caller to the callee.
That's incorrect. If the language has pass-by-reference semantics, then it does not copy the value, it passes the callee a reference to the variable. It's not true of pass-by-name, either, but don't know much about that strategy.
A good article on this topic is the documentation on C#'s ref keyword, which enables pass-by-reference. The article does a good job explaining the related concepts. [0]
The acid test for whether pass-by-reference is happening, rather than pass-by-value, is whether the asserts can fail in code along the lines of this Java code:
int myInt = 42;
doStuff(myInt);
assert(42 == myInt); // Ok
String myString = null;
doMoreStuff(myString);
assert(null == myString); // Ok
In Java, the asserts will never fail. The two methods called do not have access to either the myInt local or the myString local, they only have access to copies of the values held in the two locals. This is the reason Java would permit us to use the final modifier when declaring the two locals, without needing to know anything about either of the called methods.
On the other hand, C# permits pass-by-reference. Here we'll suppose that both doStuff and doMoreStuff declared their parameters using the ref keyword:
int myInt = 42;
doStuff(ref myInt); // If callee uses 'ref' keyword, caller must use it too
assert(42 == myInt); // May fail
string myString = null;
doMoreStuff(ref myString);
assert(null == myString); // May fail
In this case, either assert may fail, depending on the behaviour of doStuff and doMoreStuff. The callees are given references to our locals, and so they may mutate our locals (as well as reading their values of course).
Related to this, this is illegal in C#:
doStuff(ref 42); // Compile error. 42 is not a variable!
I remember learning Java when I was beginning programming and told that it was "pass by reference except for primitive types which are copied", when that's a total lie! It's not pass by reference at all. I think they said this because C++ copies objects (or nowadays, moves them) when you pass them as arguments (unless you pass by ref), and they wanted to make the distinction with C++ (i.e. "Java doesn't copy objects when you pass them to functions"). But it's done a terrible disservice to the entire industry confusing programmers for years by using the term "pass-by-reference", which has an entirely different meaning.
What people mean when they say "Java is pass-by-reference" is that "if you pass a mutable object to a function, the function can mutate it". But that's not the same thing at all.
I encountered similar confusion in faculty members as an undergraduate.
To resubmit what I wrote in a comment below:
It's confusing that we use 'refer to' in two different senses. In Java, a reference-type variable 'refers to' an instance, but overwriting the variable does not impact the referred-to entity. In pass-by-reference, a parameter 'refers to' a variable, and overwriting does impact the referred-to entity. Perhaps we should instead say that in Java, a reference-type variable 'points to' an instance.
> ...it passes the callee a reference to the variable.
And that reference itself is a value-- it's a thing passed to the function and copied from somewhere in memory to a register. It's the interpretation of this value that makes it a reference to some other tangible item. Further, it's the implementation details behind the syntactic sugar, compiler optimizations, and runtime support that allow the developer to reason abstractly with references.
Your Java example with String overlooks the fact that String is immutable: the object itself can't be modified. Use any other object type, allow doMotreStuff() to operate on the argument's properties, and you get the same effect as if passing by reference.
My point is that the SO explanation isn't a good one precisely because you get this pass-by-reference behavior in Java. Yes, indeed, technically there's this value that gets passed to a function, and it's the value of the reference. And, yes, everything that "passes by reference" has to pass something and that something is the "value of the reference" so everything is technically, at the bottom of the abstract stack, "pass by value." But that's not helpful when attempting to help the newb understand why his object mutated in a method when "pass by value" is what he expected.
"call-by-reference" already has a technical meaning, and it is widely-misunderstood because "reference" is an overloaded term.
Variables are cells that contain values. A better name for "call-by-reference" semantics is "call-by-variable", because the variable -- the value-containing cell -- is what is semantically received by the called function. Moreover, it doesn't matter how this is actually implemented, so long as a caller may effectively rebind a caller's variable.
In Java, variables may contain either "reference values" or "primitive values". It is never possible, in Java, to rebind a caller's variable. (Consider that there is never a call site that could be rendered illegal by making a non-final argument final.) We should not call it "pass-by-reference", not only because it's incorrect but because, to your point, it's entirely misleading when "reference" already has a distinct meaning in Java.
Pointers are strictly more powerful in a language than pass-by-reference. If you have pointers and pass-by-value, you can emulate pass-by-reference by providing a pointer value that points to a variable cell. So if you have pointers already, you don't strictly need call-by-reference.
C# doesn't have pointers in the managed subset, because raw pointers can't be managed. But call-by-reference can be added relatively easily, so you can recover a small amount of what could be done if you had pointers. That's the purpose of the `ref` keyword.
Java doesn't have pointers, either, but it also doesn't have call-by-reference. That makes it impossible to write the canonical example of call-by-reference, `int a = 1; int b = 2; swap(a, b)`. Instead, you must reify the concept of a cell in the first place, e.g. by wrapping each value in a one-element array, and pass those cells to `swap` instead.
> that reference itself is a value-- it's a thing passed to the function and copied from somewhere in memory to a register.
I don't see your point here. Java always passes by value. This isn't an open question. Computer architecture, assembly code, and compiler specifics, are irrelevant.
> it's the implementation details behind the syntactic sugar, compiler optimizations, and runtime support that allow the developer to reason abstractly with references.
It isn't. References types, and parameter-passing, work however the language defines them to work. The language's implementation isn't relevant.
> It's the interpretation of this value that makes it a reference to some other tangible item.
In pass-by-reference, the parameter refers to the passed-in variable, and you aren't given a choice about it. If you assign to a parameter which was passed by reference, the change will be visible to the caller. This is different from passing a pointer by value (as in C) and from passing an object-reference by value (as in Java).
(It's confusing that we use 'refer to' in two different senses. In Java, a reference-type variable 'refers to' an instance, but overwriting the variable does not impact the referred-to entity. In pass-by-reference, a parameter 'refers to' a variable, and overwriting does impact the referred-to entity. Perhaps we should instead say that in Java, a reference-type variable 'points to' an instance.)
> Your Java example with String overlooks the fact that String is immutable
It does not. The immutability of the String instance is irrelevant. Swap it out for another class type, or for an array type, and everything I wrote still applies.
> Use any other object type, allow doMotreStuff() to operate on the argument's properties, and you get the same effect as if passing by reference.
In Java, everything is passed by value, including Java's reference types. Sometimes, pass-by-value and pass-by-reference would behave the same. We could demonstrate this with a C# example. So what?
I'm not talking about accessing the members of the referenced object, as that isn't instructive here.
Using pass-by-reference would permit the reference-type variable itself to be modified. Again, it is irrelevant whether the object instance is immutable. An example where we don't use an immutable object, but it still matters that Java uses pass-by-value:
private static void doStuff(int[] arr) {
arr = null; // Only overwrites local copy. Reference types are passed by
} // value. The assignment is invisible to the 'main' method.
public static void main(String[] args) {
int[] myArr_1 = {1,2,3};
int[] myArr_2 = myArr_1;
// The value of local variable 'myArr_2' cannot be changed by this line:
doStuff(myArr_2);
assert(myArr_1 == myArr_2); // Ok.
}
> the SO explanation isn't a good one precisely because you get this pass-by-reference behavior in Java
There is no pass-by-reference in Java. It is incorrect to say that Java sometimes passes by reference. Java has reference types, has no pointer types, and always passes by value. These are distinct concepts, with accepted terminology.
> that's not helpful when attempting to help the newb understand why his object mutated in a method when "pass by value" is what he expected.
Maybe so, then we should start by explaining Java, and only explain the terms pass-by-value and pass-by-reference later on.
What we shouldn't do is teach an incorrect definition of pass-by-reference. Saying that Java uses pass-by-reference is simply wrong, and should cost a student marks on their exam.
That's exactly what "pass by reference" means. According the SO definition, C is always pass by value: the value of the 'primitive' (int, long, char) or the value of the pointer (an address.) It pretty much applies to any language: ultimately you're passing a value from the caller to the callee. Whether that value is 'raw' (say, an int) or a pointer or reference is all in how you (or your compiler, or your runtime) interpret that value you received.