Java is pass-by-value, Dammit (and so are Ruby and Python, Dammit)
javadude.com
javadude.com
Ok, I think the real losers in this discussion are the ones who fail to see both sides of the issue. We can cherry pick "refrence" definitions if we want, but really the nuts and bolts come down to this: Passing by value means that a copy of the parameter is made when the function is called and any changes to that variable will not be reflected outside of the function. Passing by reference means you pass a pointer to your data (and nothing more) so the function can dereference the parameter and affect data that exists outside of the function.
All non-primitives in Java are implicit pointers, so when you pass one of these into a function, you are passing a pointer (or reference) to data that exists outside of the function. However, the reference itself, as it exists inside the function, can be changed to point toward something else. Essentially, the implicit pointer is passed by value, and that value can be altered without affecting anything outside the function.
So technically yes, you could get away with calling this pass-by-value. However, the spirit of pass-by-reference is maintained for any part of the data that most people care about. The syntax is different from a pass-by-reference in C++, and there's a silly little trick you can do by changing the reference pointer (or silly trick you can't do by changing the pointer outside the function) but for all practical purposes you are doing the same thing.
In my opinion, if you want to insist that Java strictly follows pass-by-value, then I think it has ceased to be a relevant distinction.
As stated in the original article, pass-by-value and pass-by-reference have well-known definitions within the computer science community. There is no ambiguity here.
When we excuse the lazy use of such terms incorrectly, we hamper the ability to communicate clearly and effectively. Please stop.
The core misunderstanding seems to be a conflation of 'pass a reference by value' and 'pass-by-reference'.
Passing a reference by value != pass-by-reference. The End. Q.E.D.
Pass-by-reference means that the compiler takes a reference of (or, getting a pointer to) the parameter passed in to the function. This is not the same as passing an existing reference (pointer) to the function (by value). Java only allows the latter (primitive types aside).
A side issue is that some developers mistakenly believe that pass-by-value roughly implies a deep copy, and thus that the 'spirit' of pass-by-reference is the avoidance of a deep copy.
I would posit that many C++ functions that operate on object parameters do so via a pointer (a.k.a. reference) passed by value, just as Java does:
void modify_my_object(MyClass *myObject) {
myObject.setName("New Name");
}
int main(void) {
MyClass *myObject = new MyObject("A Name");
modify_my_object(myObject);
// myObject.name is now "New Name"
}
This is pass-by-value, and there is no deep-copy happening there.Just because many developers don't take advantage of (or don't understand the semantics of) pass-by-reference does not excuse ignorance of the well-known definitions of those terms.
And if there's any time you can afford to be loose about the spirit vs. the "technical" letter of the thing, it's when you're talking to a compiler. Right? I agree with the article. If you don't like the meaning of a technical term with a clear meaning, or if you simply don't have any occasion to use it properly, that's no excuse for repurposing it in the same context to mean something different that leads to confusion.
It's worthwhile to remember that (true) pass by reference isn't just a curiosity from obsolete languages. It's common for people entirely new to programming to expect that function parameters might, or actually do, work that way. The terms are at least useful to explain things to new learners.
In my opinion, if you want to insist that Java strictly follows pass-by-value, then I think it has ceased to be a relevant distinction.
Even if you work only with pass by value languages, you should still respect the terminology. Some mathematicians only work with continuous functions, but they don't say, "Hey, this word 'continuous' would be a lot more useful if we redefined it to draw a useful distinction among the functions we actually work with." So "pass by reference" doesn't mean what you want it to mean and doesn't seem very useful to you. Invent your own terminology. Don't destroy existing terminology by sowing confusion. And that's all you can accomplish -- there are too many people walking around who already know what "pass by reference" means for you to get away with redefining it.
It's a relevant distinction because it's required to explain code behavior.
I think this distinction ceased to be relevant in the late 70's...
Object x = null;
makeString (x);
System.out.println (x);
void makeString (Object y)
{
y = "This is a string";
}
Maybe it's just a disconnect between theory and practice?I use this as an interview question, too ("Is Java a pass-by-reference or pass-by-value language?") Nobody ever gets it, but I let people choose one of several languages to be quizzed about, and the ones who know this kind of terminology are usually game to pick a more difficult language. I don't hold it against them as long as their explanation of why Java is pass by reference shows a correct understanding of Java parameter passing. But I always set them straight afterwards ;-)
Java sets up an environment where the parameter passing behavior just isn't surprising. If you've been programming in Java for a little while, it's very easy to have an intuitive feel for how parameters will act, without having to go back to theoretical principles.
Knowing about the theory behind pointers, pass-by-value, and pass-by-reference will still make you a better programmer. But Java's a stronger language for not requiring that knowledge.
So although Java's behavior is simple and consistent, the parent comment seems to flatly contradict your assertion, "If you've been programming in Java for a little while, it's very easy to have an intuitive feel for how parameters will act." It's also a perfect example of how programming in Java, or in fact any language with a parameter-passing mechanism and mutable variables, does require that knowledge, so your assertion that "Java's a stronger language for not requiring that knowledge" is nonsense.
That said, I stand by "not requiring that knowledge". Java's behavior is understandable without having to know about value and reference semantics. That doesn't mean it doesn't require any knowledge. Specifically, I think it requires two points: (1) Variables are just names, so reassigning a variable doesn't change anything else in the system; (2) When you call a method on an object, you might change that object.
In support of this: I've also been doing a lot of interviews recently. In my (admittedly limited) experience, the people who have had trouble with Java's parameter passing behavior are more experienced developers who've done a lot of work in other languages. Their confusion isn't from Java's behavior, it's the caution about pass-by-reference that they've brought over from C and C++. I don't really see junior people making this mistake. So I suspect having just a little knowledge of the value vs. reference issue makes Java harder to understand, by bringing up new and confusing possibilities.
But, like I said, my experience is limited. If you do see new developers being confused by this aspect of Java (or Python, Ruby, or other languages with similar semantics), I'd be interested to hear about it.
Alternately, it could mean: "I was reading LiveJournal five minutes ago, and haven't quite finished switching over to the Hacker News house style." ;)
Do you really maintain stuff like this in your codebase?
What about languages that are immutable by default, like Haskell, OCaml, and Erlang? You can't write a swap function. Therefore, are they pass-by-value?
Actually, in OCaml, you can write the swap function.
let swap a b =
let temp = !a in
a := !b;
b := temp
let x = ref 3 in
let y = ref 8 in
swap x y
But now, you are passing references by value, as Java does. So maybe they are pass-by-value. But, when your language is immutable, pass-by-reference (whatever that would mean), doesn't effect the language semantics. They are pass-by-(it's-moot).Even the putative "true" definition is usually only the "true" definition in the context of machine language, and something like a true Lisp machine might still end up with no applicable definition for common terms.
(Every time I say this, someone tries to correct me, but it is followed up by someone who then tries to debate the definition being used to correct me. It really is all relative.)
So, in this case, the definition being given for "-by-value" vs. "-by-reference" does hold across a wide variety of imperative languages, but as you point out has no meaning in strictly-immutable functional languages since even inside a given function you can't write a "swap", let alone as a function. The terms only have meanings in certain contexts.
The fact is the usefulness of these concepts depend on what language you're writing in. In java, where pointers aren't explicit, you need to know when you're assigning a variable a memory locale versus a value. In C++, where pointer assignment is explicit, that's not a useful concept, so pass-by-reference has a different meaning.
I honestly think we should come up with a different name for pass-by-reference the way it is used in C++. It's not like people actually write code using pass-by-reference anyway :D.
It's a symptom of language, and it's impossible to stop.
So I think the lack of a real computer science today, and the lack of real software engineering today, is partly due to this pop culture."
Full conversation: http://queue.acm.org/detail.cfm?id=1039523
In Shakespeare's day, his plays were ribald entertainment for the masses. People are continuously complaining about how the old ways were better, and one is entitled to one's opinion, but the old ways are in the past and gone. Soon the last person who remembers them will be dead and there will be no one to complain about it, so what's the point?
"In the last 25 years or so, we actually got something like a pop culture, similar to what happened when widespread literacy came on the scene and some of its perpetrators thought it would be a way of getting the Bible to the masses. But they forgot that you have to be more sophisticated and have more perspective to understand the Bible. What books were able to do was capture people as they were."
For a better explanation than I could ever come up with: http://stackoverflow.com/questions/986006/python-how-do-i-pa...
Just to play devil's advocate: if it looks like a duck and quacks like a duck, why would I call it anything other than "duck"? It may be technically correct to say that (in Python, at least) everything is passed by value. But if it helps someone remember that lists may be altered when passed to a function and that tuples can't, what's the real harm?
Again: devil's advocate.
The Effbot suggest we call Python call semantics for 'call-by-object-reference' http://effbot.org/zone/call-by-object.htm which makes it a lot clearer.
After all, the issue here has nothing to do with parameter passing and everything to do with object design. It's important to understand that tuples are truly immutable and what the implications of that is.
Misuse of tuples and lists are one of the biggest problems I see in novice (and often not so novice) python code. How often do you see someone copying tuples (often inadvertently) when list semantics are far more efficient? That stems from a fundamental misunderstanding of immutability, something that might stem from not understanding how parameters are truly passed in the language.
In the original sense of the phrase, I believe, that thing was the variable itself in the form of an alias, not the object/value that a pointer variable might be pointing to.
1) Those of us who are language users care about use of the language from the perspective of the question, "If this thing gets passed in and I change it, does that change flow back to the calling method." Our perspective of pass-by-reference vs pass by value may originate from experiences learning C. We're probably wrong.
2) This guy is from the community of compiler people. He cares about implementation, and is probably correct.
We need a spoken language abstraction that allows people to discuss the things they care about, and then be able to distinguish between them. The people in the position to cry 'get off my porch' are in the best position to point the rest of us is the right direction.
If you don't understand that it's pass by value of references for non-primitives then you won't understand why your variable x is null after the method call:
Object x = null;
fooMe(x);
//is x null or a Foo?
[...]
void fooMe(Object y){
y = new Foo();
}
That's fundamental knowledge.Right: pass by value, of references. That's the complete answer, and it's really misleading to say anything else.
I don't think any Java programmers actually have any misunderstanding here, even the worst of them know how this works. What's the problem?
Also, the article tries to use code like this:
void swap(SomeType& arg1, Sometype& arg2) {
SomeType temp = arg1;
arg1 = arg2;
arg2 = temp;
}
to prove how different references in C++ are from Java.But the reason something like that might work in C++ is not that the semantics of parameter passing are different (references cannot be reseated in C++ any more than in Java), but that C++ uses the assignment operator to overwrite the contents of the lhs, and invokes the copy constructor automatically. The true equivalent code in Java works just fine, assuming the copy constructor and set method do the right things (which is a potential pitfall in C++, as well):
static public void swap(SomeType arg1, SomeType arg2) {
SomeType temp = new SomeType(arg1);
arg1.set(arg2);
arg2.set(temp);
}The only reason that code won't work for Object is that you can't add a copy constructor or "set" method to Object, not because of any difference in reference semantics. In a real-world implementation we might try to simulate duck-typing by accepting an Object and using reflection to check for the appropriate methods on the object, and though it would be a bit slow it would work for any object type that had the methods defined.
My main point was that for any type SomeType that lets the Java code compile, it will do exactly the same thing as the analogous code does in C++, assuming you've defined the class methods appropriately. Which makes it a very poor illustration of the difference between reference semantics in Java and C++.
The abstraction of "this thing" getting passed is certainly useful. However, things are clearer if you imagine two variables which happen to be defined in different scopes being set to the same object. Hopefully these questions are trivial to any Java programmer:
If you have two variables set to the same object, and then change the object, are the two variables still set to the same object? Yes.
If you have two variables set to the same object, and then set one of the variables to a different object, are the two variables still set to the same object? No.
Do any other languages besides C++ allow this definition of pass-by-reference? The reason I ask is that it seems silly for me to change the way I talk just to satisfy one language that i don't even code in.
And if so, when would it actually be practical to use this? The idea of reassigning a parameter in a function and then having that reassignment affect variables OUTSIDE the function sounds very strange to me (and possible even dangerous).
There are classes of problems that these type of true reference semantics can be quite helpful. In C/C++ the technique is largely used in contexts where you want to return multiple values from a function, as there is no native support for dynamic tuples. Such is the way of statically typed languages.
There are also cases where this type of reference to a pointer magic can really improve the efficiency of the algorithm.
True reference passing is a tool. For those living in dynamic languages (as I do now), not a particularly relevant one. But that doesn't make the distinction any less important.
def swap(a, b):
t = a
a = b
b = t
def swap2(a, b):
t = a['v']
a['v'] = b['v']
b['v'] = t
x = 3
y = 8
xx = {'v': x}
yy = {'v': y}
swap(x, y) # changes nothing
swap(xx, yy) # changes nothing
swap2(xx, yy) # changes 'v' values in xx and yy, but not x or y a, b = b, a
:) def swap(a,b):
a,b = b,a
does not work.1) Variables being references(pointers) to objects.
2) Function arguments being passed by reference or by value.
In Python, all variables are pointers to heap allocated objects, and these pointers are simply passed by value when calling functions.
In C++, it is much easier to understand this distinction as it provides full control to the programmer on both aspects.
def foo(my_list):
my_list = [ "my", "new", "list" ]
Executing this function will not change the value of the list passed to it, it will create a new list and reference it locally. If calling foo(old_list) caused old_list to now contain [ "my", "new", "list" ], then it would be pass-by-reference in the sense this article refers to.EDIT: To clarify, you can mutate mutable arguments in-place, but you can't change what is being referred to by the identifiers used to refer to these arguments outside of the context of the function, which is what is meant by pass-by-reference in the article.
The problem (discussed by the article) is that "pass-by-reference" is a term that is used a couple of different ways. By someone's definition, this property of Python objects might cause them to consider the calls to pass-by-reference, but the way the author defined it in this article they are not.
You can modify the original list in your example by having foo() call my_list.append("pwnd!"), for example. You can even use id() to verify that it really is the exactly same object that is visible to the caller and the callee.
Python doesn't pass by reference (in the aliasing variables C++ sense) and it doesn't pass by value (in the functional sense) but rather, it passes references.
Everything is an object anyway but objects aren't copied around. They're just bound or rebound to new variables.
In the above example Python creates new local variables for all function arguments and binds them to the objects passed in as arguments.
If those local variables are assigned to, they're just rebound to point to the new local object while the original variables in the caller code still remain bound to the original object.
I disagree that there is a right or wrong to this - C++ was made to be a generic programming language and thus gives many options to the programmer. If by "do it right" you meant "hide all options except the one most commonly used" okay. Otherwise I strongly disagree with that sentence especially because I use different kinds of "pass-by" whenever I program in C++ and will be using rvalue reference from the C++0x. Different languages suit different needs.
vector<int> numbers; void f(vector<int> args);
Due to C++'s copying, args[0] has a different address than numbers[0], because a deep copy of the vector was made. As the article states, this is not what pass-by-value is referring to, otherwise it would be false that Java / Python / Ruby et al are pass-by-value. So I disagree that the terms are clear, but rather that there is confusion around these terms. As for wanting immutability, it's almost always better for C++ code to write functions not like f but instead like this:
void g(const vector<int>& args);
And apologies for the editorializing, but I do consider this a language design flaw, one inherited from the backwards compatibility for C, which already allowed struct's to be passed (non-pointer) as args and then copied to keep the caller untouchable. It makes C++ code more verbose and more error prone, and is quite difficult for new programmers to grasp.
If I wanted to write a function that accepted a vector and returned a slightly altered version of that vector I would make a function that does a deep copy and would return that - without ever needing to call the copy constructor myself. I think that it is nice that C++ gives me that option. I don't think that any language is flawless and it's clear that one programmer's feature is, in this case, another programmer's flaw. Keep in mind that this applies to your favorite languages as well.
Edit:
It occurs to me that the distinction is important in multithreaded programs as well. Beyond just worrying about whether or not the underlying data structure is thread safe, passing something by reference might mean sharing memory between two CPUs which can easily lead to a slowdown as the CPUs need to repeatedly flush and resynchronize what's in their cache. Thus unless I have specifically built a thread-safe class whose data has a real need to be shared between between threads I would send data from one thread to another by value rather than by reference.
The problem with the C++ approach is that it's default (pass by copy-constructor really) is rather implicit. Your doing a potentially a ton of work with a very innocent function call, with possible side-effects. At least the 'pass a reference by value' behaves the same way EVERY time.
For example, in C++:
myobj a; somefunction(a);
That copy constructor might trigger a database hit to create a new object if myobj was some sort of ORM. It might call 23 other constructors to fully complete it's deep copy. Who knows, as it all happens rather implicitly. In python, that would look like:
a = myobj() somefunction(a)
def somefunction(p): p = copy.deepcopy(p)
In that version I'm now implicitly providing that copy. In your multi-threaded example this is still better, as I get the best of both worlds. Ya, I might lose a bit of convenience... but that explictness is worth the trade-off IMHO.