views:

287

answers:

6

I read something online that incorrectly stated that standard int [], etc arrays in Java were passed as copies, rather than passing references to the arrays, in analogy with the basic numerical types, and ended up overwriting an array when I thought I was modifying a copy. Can I chalk this up as a design choice to make things simpler to the target audience for Java circa mid-90s? (making objects look the same syntactically as C arrays, or are arrays really not of type "Object" in Java?)

That is, why didn't they just do something like:

Array array = new Array(<size>);

Additionally, why didn't they make everything (except literals) pass-by-reference to ensure consistency? (ints would then be passed as references to the int, not as the value of the int, so modifying a variable that's an argument of a method within that method would modify the value of the original variable, etc.)

Link to a discussion of pass-by-reference vs. pass-by-value in Java

+11  A: 

Nothing is passed by reference in Java - but you need to know what the value of a variable is.

The value of a variable of type int[] is not an array. It's a reference to an array. All arrays are reference types, even if it's an array of primitives.

When you write:

int[] x = { 1, 2, 3, 4, 5 };
someMethod(x);

then the value of x is passed by value to someMethod. It's a reference to an array - the method can change the contents of the array, but it won't be able to change the value of x itself, which it could do if Java used pass-by-reference.

Once you understand that the value of any expression is either a reference or a primitive value, a lot of things become clearer. For example, take this code:

int[] x = { 1, 2, 3, 4, 5 };
int[] y = x;
y[0] = 10;
System.out.println(x[0]);

What would you expect the result to be? The assignment operator copies the value from the RHS to the LHS - so x and y are references to the same array. Therefore the final line prints out 10. This "copying the value" is exactly the same principle used for argument passing.

There's no inconsistency here - you just need to understand what's going on, and what pass-by-value and pass-by-reference really mean.

EDIT: I'm really surprised there's still any doubt about this.

From the Java Language Specification, section 8.4.1 (Formal Parameters):

When the method or constructor is invoked (§15.12), the values of the actual argument expressions initialize newly created parameter variables, each of the declared Type, before execution of the body of the method or constructor

That's practically the definition of pass by value semantics: the values of the arguments are used as the initial values of the parameters.

Those values may be references or they may be primitive values - it doesn't change the fact that it's the value which is passed.

EDIT: The definition you use, while badly expressed in my view, certainly does not mean that claiming Java passes everything by value is misleading.

It says, for pass by value:

This makes a copy of the variable and can be quite slow and inefficient if the variable is large like an array.

Note that it was talking about C and C++ (although C++ does have pass by reference as well, in fact). It talks about making a copy of the variable. That's exactly what Java does. The difference is that in Java, the value of the variable is always either a primitive value or a reference. It's never an object.

Once you understand that crucial point (and it's important for more than just argument passing) it's entirely straightforward to correctly say that Java passes everything by value. When a method or constructor is invoked, the arguments are evaluated and the values are used as the initial values of the parameters. That's pass by value, and that's what Java does for all parameters.

As for the PDF you linked to - that's a shamefully poor discussion of the topic, IMO. It makes a mess of what pass by reference means, it special-cases String for no good reason (String happens to be immutable, but other classes can be too) and it's generally wrong. Would it help if I gave some links supporting my point of view?

There are hundreds more. You aren't the first one to be confused by this, but Java really does pass everything by value, even references.

Jon Skeet
@Downvoter: Care to comment? Which bit do you disagree with?
Jon Skeet
You confuse pass by value and pass by reference, see the link in the question above. "Even references are passed by value" is incoherent, because passing a reference as a reference is a different level of indirection.
cons
@cons: passing by reference means that the called function can mutate the value of the variable used as an argument. Java does not provide a way to do this. If I call f(y) in Java, whether y is an object or a primitive value, there is no way to change y within f() so that it points to a different object or primitive value. If y is an object, you can change that object (if its methods permit) but you can't change y.
Jason S
+7  A: 

Everything in Java is pass-by-value. Everything. In the case of Object types (which arrays are), what gets passed by value is the reference. No, that's not the same thing as pass-by-reference.

Michael Borgwardt
+1  A: 

Yes, int[] is an Object. Yes, the syntax was to get C/C++ programmers in. No, it's not a poor design choice, the two statements are not contradictory.

skaffman
+1  A: 

From at least a performance perspective, it makes a lot of sense to pass arrays by reference. Otherwise you would need a lot of unnecessary copying.

That having said, I agree that there should be an immutable array object.

Thilo
A: 

This is a common misconception about what it means for Java objects to be "passed by value." ALL Java objects, arrays, and primitives are passed by value, but in the case of objects and arrays, the value that's passed is in fact a pointer (or, if you'd like, reference) to the original object.

Here's the difference. In both Java and C++, I can write this function:

void myFunc(int[] arr) {
    arr[0] = 17;
}
myFunc(myLocalArray);

This, in either language, causes the value stored in arr[0] to be 17 both inside myFunc's "arr" variable and inside myLocalArray.

This is very exciting, of course, but has nothing whatsoever to do with "pass by reference."

Passing an array by reference means that, in a language like C++ (but NOT in Java), I can do this:

void myFunc(int[] arr) {
    arr = null;
}
myFunc(myLocalArray);

Here, I've completely replaced the myLocalArray object with an entirely different object (null, in this case, but it could be anything). I haven't merely modified the object (e.g., changed the value stored at a particular index), but rather have fundamentally erased all evidence that myLocalArray ever even pointed to a legitimate array.

In Java, that cannot ever be done.

So, the basic rule in Java is:

  1. All edits WITHIN the object (e.g., calls to functions that alter state, direct alterations of state, changing values in an array, et cetera) act on the original object (i.e., in the calling function). No copy is ever made without you specifically making it.
  2. Completely overwriting the local object with a new one will NEVER affect the object in the calling function.
VoteyDisciple
It's incorrect to say that "objects and arrays" are passed by value. They're never passed at all. *References* to objects and arrays are passed. Likewise it's misleading to talk about the variables as if they are the objects. I know this is picky, but I think precision is important when discussing things like this.
Jon Skeet
Your C++ example isn't correct (the one where you try to set `arr` to `null`).
Daniel Earwicker
I was deliberately a bit vague on the syntax to better illustrate the concept: you can, in certain circumstances (i.e., when it's passed by reference) set "arr" equal to something in C++.
VoteyDisciple
+2  A: 

Yeah sure. There is no denying that a memory address is also a value. So pass-by-reference really is just a special case of pass-by-value.

+1 for the most Filistine answers ever on SO.

BTW, I think I might also have a portion of an answer to

"why didn't they just make everything pass-by-reference to ensure consistent behaviour?"

In that case, how does the system deal with invocations where the arguments are literals, say 'result = f(2);' ?

Must that literal then not also be passed by reference ? And if that is so, would not that open up to the possibility of having your literals changing value by some invocation that updates the reference ? In which case the term 'literal' might become somewhat inappropriate, and a lot of possible code optimizations become impossible for the compiler to implement ?

Everything in a computer is really a value, but that's beside the point :)
cons
The point isn't the representation in the computer, it's the representation in the language itself. The computer (or rather the compiler/runtime etc) merely implements the language. The important point is what the *language* says - and at that point, pass-by-reference is certainly *not* a special case of pass-by-value. It's a specification of how the value of an argument may be affected by the method it's passed to.
Jon Skeet
Isn't that just a roundabout way of saying Java doesn't support C-style pointers, which of course it doesn't? The references are there, and are being passed around, you just can't modify them yourself like you can with pointers in C. That's different than saying everything is a value, because you have to make the distinction between values and references in order to support data structures like linked lists, etc, or anything that requires references to other objects to work.
cons
C doesn't have pass by reference either - it's strictly pass-by-value, like Java. There's a big difference between "reference" as a concept and "pass-by-reference" as an argument/parameter-passing mechanism. Obviously they're related, but they shouldn't be conflated. C# doesn't have C style pointers in "safe" code, but you can still use pass-by-reference with the "ref" modifier (at both call site and method declaration).
Jon Skeet
"Pass by Reference passes in a reference to a variable - this is effectively the address of the variable into the function." would be the definition I'd be using. You can pass pointers as arguments in C, and you do it all the time in Java, hence the null pointer exceptions.
cons
Jon Skeet
Answering to "That definition is in terms of how to implement pass by reference by passing a pointer by value."That is so correct. But it is YOU who is confusing model and implementation. At the "model" level, java DOES know the concept of "pass by reference" (precisely BECAUSE java implementations pass around pointers). Which is what inspired your answer that "everything in java is really pass-by-value", because you were looking only at what an implementation is required to do, and because you didn't seem to understand that the question was more intended at the "model" level.
@Erwin: Please show me where the Java language refers to it having pass by reference. It doesn't. The Java language models *everything* in terms of pass by value.
Jon Skeet