top | item 1956497

Java is Pass-by-Value, Dammit

9 points| m0th87 | 15 years ago |javadude.com | reply

12 comments

order
[+] Edmond|15 years ago|reply
Good post.... I am a Java developer with almost 10 yrs of experience and I know I often make that mistake even on Job interviews:).... The problem is that people used to Java tend to think more about the intuitive consequence of passing by ref vs value. When a Java dev thinks of passing by reference he's thinking: "I can alter the state of the reference and the changes would be visible globally, including from within the calling context". In other words Java devs think about altering arguments in terms of altering their state as opposed to altering the reference which is just a numeric address to a memory location. People who program in languages lacking object/class-like structures are more aware of the need to use parameters both as arguments and return values, something that is foreigner to Java programmers.

I haven't done any serious C++ programming in years and I have to admit the examples you used to demonstrate your point; ie modifying the value of arguments appears very strange to me now, I obviously did a lot of that when I did C/C++ development but not having done it in such a long time it really does seem like an unusually way of getting return values:)

[+] runT1ME|15 years ago|reply
Almost EVERYONE I've interviewed, including senior programmers, think that if you do this:

   void nullThis(Object o) {
      o = null;
   }
   Object o = new Object;
   nullThis(o);
   System.out.println(o.toString());
throws a NPE
[+] SeanLuke|15 years ago|reply
Java is in good company. Lisp is also pass by value.
[+] binaryfinery|15 years ago|reply
Passing an object by reference is the same thing as passing an object reference by value. It is just semantics. Its not even splitting hairs. Its demanding that his specific definitions are somehow more correct than any other.
[+] okmjuhb|15 years ago|reply
This is not at all correct because passing by reference and value have defined and distinct meanings. Consider the difference between C++, which has actual pass by reference: void swap(int& x, int& y) { int t = x; x = y; y = t; }, and Java: void swap(Integer x, Integer y) { Integer t = x, x = y; y = t; }. The C++ version will result in changes to the variables in the calling function and the Java version will not.

The real problem is that Java created needless confusion by calling its pointers references for purely marketing reasons.

[+] nostrademons|15 years ago|reply
(Can't reply to the other subthread, it's apparently tripped HN's "this is too heated" trigger, so I'll explain here.)

It's easiest to illustrate this with code:

  public class ValueHolder {
    public ValueHolder(int value) { this.value = value; }
    public int value;
    public static ValueHolder THREE = new ValueHolder(3);
  }

  public class DoSomething extends TestCase {
    public void passByValue(byvalue ValueHolder value) {
      value.value = 1;
      value = new ValueHolder(2);
    }

    public void testPassByValue() {
      ValueHolder myValue = ValueHolder.THREE;

      passByValue(myValue);
      assertEquals(ValueHolder.THREE, myValue);
      assertEquals(3, myValue.value);
    }

    public void passByReference(byref ValueHolder value) {
      value.value = 1;
      value = new ValueHolder(2);
    }

    public void testPassByReference() {
      ValueHolder myValue = ValueHolder.THREE;

      passByReference(myValue);
      assertNotEquals(ValueHolder.THREE, myValue);
      assertEquals(2, myValue.value);
    }

    public void passReferenceByValue(ValueHolder value) {
      value.value = 1;
      value = new ValueHolder(2);
    }

    public void testPassByValue() {
      ValueHolder myValue = ValueHolder.THREE;

      passByValue(myValue);
      assertEquals(ValueHolder.THREE, myValue);
      assertEquals(1, myValue.value);
    }
  }
Syntax is slightly made-up because Java doesn't have true pass-by-value or pass-by-reference for object, only pass-reference-by-value. But the test cases illustrate the expected semantics for each parameter passing mode.

In each case, you're passing a mutable object containing a value to the function. In pass-by-value, you pass a completely new copy of the object in, so the mutation doesn't affect the original object at all, and then the reassignment obviously doesn't propagate back to the caller. In pass-by-reference, you pass in a reference, so the mutation changes the object in the caller's scope, and then the assignment reassigns the variable in the caller's scope to the new ValueHolder. It's this last part that pass-reference-by-value can't do: normal Java semantics let you mutate the object passed in, but you can't make the variable in the calling frame actually point to an entirely new object.

Make sense?