Java is Pass-by-Value
javadude.com
javadude.com
In fact, you can write a swap(x,y) function in Java. It goes something like this:
class foo { int value }
void swap(foo x, foo y} {
int temp = x.value;
x.value = y.value;
y.value = temp;
}
(Yes, I know this isn't valid Java. Cut me a little slack here, OK?)"But that's cheating" you protest. "That's not swapping the value of X and Y, that's swapping the value of a slot in the values of X and Y, which happen to be objects." Well, yeah. So? Compare that to this C code:
struct foo { int value }
void swap(struct foo x, struct foo y) {
[same code as above]
}
The effect of this function will be DIFFERENT. Specifically, the C function will have no effect while the Java function will swap the value slots of X and Y because C lets you pass a structure as a value while Java does not. All Java "values" are (tacit) pointers to objects [1]. Pounding your fist on the table and insisting that Java is pass-by-value because you can't write a swap(x,y) function obscures this crucial difference.[1] OK, it also has ints and floats of various sizes. But that's really it.
Pedantry matters in our profession. Details have consequences.
I didn't say it was. I said that insisting it is pass-by-value isn't helpful.
The real problem here is that we have only two terms which we're using to try to distinguish between three different concepts.
Having thought about it for a minute or two, it seems pretty silly to me . Types are all about restricting the set of values an expression can have, and restricting the set of operations you can perform on an expression, such that any operation you're allowed to perform on a value will always do something sensible. Untyped languages don't do that, which makes them quite different from typed languages. But then i've only thought about it for a minute or two.
I could imagine a genuinely unityped language. Perhaps one where every value is a vector of real numbers with an infinite number of zeroes on the end, and the operations are piecewise arithmetic, dot products, interleaving, appending, etc. That would behave quite differently to the languages where you get "undefined is not a function" and friends.
I think Harper would take issue with it being explained this way, but one can think of Ruby and Python being languages where everything is a pointer to a HashMap and everything else is just sugar on top of that (similar to the above argument about Java and the sugar with the pointers).
I don't think Harper would like that way of explaining it because it's over-focused on an example instead of sticking to the concept and because it conflates (statically-knowable) types with (runtime) classes, which is big no-no with him.
This is in contrast to, say, Java, where (2/3) can be part of a valid program, but ("abc"/3) cannot, so 2 and "abc" cannot belong to the same equivalence class.
Yes. Python e.g. is more unityped (union typed, things have a type, but are handled as a union among several options) than untyped. tcl, on the other hand, is more untyped (everything is the same thing: string-like).
The whole “pass by x” really confuses things. It’s really more “represented by foo” underlying the passing that is important.
It's still only two concepts, there's just the side effect of Java and friends' implicit pointers that makes things muddier. The Java function
void swap(Object x, Object y) {
Object temp = x;
x = y;
y = temp;
}
is equivalent to the C program void swap(void *x, void *y)
{
void *temp = x;
x = y;
y = temp;
}
and it has the same bug for the same reason. It's only the implicit nature of references in languages like Java that makes it not look like pass by value, but that implicit nature is there in other places as well (eg, the Java code 'Object x = y' is equivalent to the C code 'void *x = y').I think the best approach is to just call it what it is, pass by value, and then also remind people if need be that objects are always pointers so it's passing a pointer by value.
I respectfully disagree. Pointers are part of the Java implementation, not part of its abstract computational model. Calling it pass-by-value when the values being passed are deliberately hidden from the user is a recipe for confusion.
Its abstract computation model is entirely equivalent to if someone did `typedef object_val *Object`, made `.` do the same thing as `->` and got rid of `->`, and then said you could only have `Object` variables, not `object_val`s. Saying that that's enough to make it not pass-by-value anymore seems ridiculous (especially when Java does still have primitives). If that were enough to make it something else, then following a style guide for C could make your code not pass-by-value anymore.
I understand what you're saying about the helpfulness to learners, but I think that they would be better served by just learning that Java classes are all reference types, their value is a reference to an object that '.' dereferences and so on, and that even if you don't want to use the word 'pointer', they happen to behave exactly like pointers. The reason I think that's better is because it also covers other common mistakes, like initializing multiple variables to the same instance and expecting copy semantics. The same mistake is being made in both that and the swap function from earlier, but the term 'pass-by-value' could only be to blame for one of them. Once you have your head around reference types, there's no problem with calling it 'pass-by-value'.
0: https://docs.oracle.com/javase/specs/jls/se8/html/jls-4.html...
Dog d means "a pointer to a dog object"
By forcing "pass-by-reference" to mean two things you are creating ambiguity that is trivially resolved by correctly interpreting a java type signature.
Yes, but the two variants that matter most are both pass-by-value.
There is not a single language in common use today that is pass-by-reference by default. In fact, only C++ (and Pascal, but who uses Pascal any more?) even allows this as an option.
And they are perfectly distinguished by being value types or reference types.
You are insisting that the definition is changed. Emulating call-by-reference in a call-by-value environment does not change the semantics of the language.
Just accept that the meaning you project to these terms is different from their real meanings. Don't try do redefine them and convince the rest of the world that your meaning is the right one.
I do also think lisper is absolutely terrible at making that point.
Every single one of these arguments between call-by-value and call-by-reference I've seen always fall apart because the arguers never accept that there's (at least) 3 forms of calling, whatever we want to call them.
> and sometimes called pass-reference-by-value in some communities
Or call-by-value-of-reference. It's too much of a mouthful, but is the usual alternative I hear.
Furthermore, the term is so useless, that most people only encounter it in debates about its meaning.
As calling conventions, pass-by-value, pass-by-reference, pass-by-name.
Then there is another meaning that comes from misunderstanding the exact definition or trying to guess the meaning. Lisper is trying to argue for that. This definition is not used anywhere where programming language semantics is written down. It lives in the realm of blogging and forum postings.
Ask some linguists - language is not math, it is more like biology. Context matters. People decide for themselves. e have no UN body that defines for each and every person in the world what something means.
What you refer to is that some groups of people WILL indeed define something, but that is for their own special communication in their field. Nobody is bound to that definition either, even the very same people may use the same word much more loosely in a different context.
We have lots and lots of words that have different meanings in different context and/or to different people. That's okay -language is as human as we are.
Nobody owns language. People decide for themselves what they want and how they use it. The "authorities" - the linguists compiling things like dictionaries, do so by looking at how people use something, and then they document the many different usages as they appear. You can only dictate language when you have a means of control over people outside of language, or if you get others to agree.
.
In response to mark-r:
Meanings change all the time, often the original idea is not even part of a new meaning any more. So asking what someone who first used a word meant is useless too.
Well, if so, even more reason NOT to say "Java is Pass-by-Value".
Instead, you should be a good pedant, and explain the Java passing model, its caveats and edge cases, in its entirety.
If details matter, don't throw some BS blanket statement like "Java is Pass-by-Value" around, that can be misinterpreted in 200 ways, and that doesn't capture the whole nuances of what's going on.
"Pass-by-reference" is simply wrong, as it implies behavior which Java does not exhibit.
[1] https://en.wikipedia.org/wiki/Evaluation_strategy#Call_by_sh...
Well, that doesn't apply exactly to ints and longs though...
Plus, I'd argue it's a lot easier to teach the nuances from the beginning rather than have to break someone's assumptions 4 years down the line (e.g. the traditional time of an undergrad CS education).
Of course, this kind of discussion isn't new to the Python community either. The actual calling convention is somewhere between call by value and call by reference, sometimes called "call by object". This is well worth reading: http://effbot.org/zone/call-by-object.htm
Yes it is. The thing that we talk about when we talk about "the value of foo", in Java, is passed by reference.
> Yes it is.
And this is my point in a nutshell. This argument will never be resolved, and so continuing to argue over it isn't helpful no matter how hard you pound your fist on the table.
But don't take my word for it. Pass-by-reference was understood by the person who invented the calling style used in Java (Barbara Liskov) not to apply to that calling style. [1] The argument was resolved before it could even be had, 44 years ago.
[1] https://en.wikipedia.org/wiki/Evaluation_strategy#Call_by_sh...
That's not what the term means and you know it. The difference between passing by reference and passing by value is that in the plain meaning of the words (all terms eventually come to mean their plain meanings, because language is defined by consensus): whether the called function receives a value, or a reference to the value in the caller's scope. Java is the latter (for non-primitives); you can tell because the called function can modify the value in the caller's scope.
If you want a term to mean "allows changing the binding in the caller's scope", coin one, but pick words whose plain meaning matches the meaning you want.
Pass-by-reference has meant exactly what I described, for at least 44 years, when Barbara Liskov decided it didn't apply to the calling scheme she invented, which was later inherited by Java.
Read: https://en.wikipedia.org/wiki/Evaluation_strategy#Call_by_sh... Specifically, "it is not call by reference because access is not given to the variables of the caller, but merely to certain objects."
I'm sure you know this, but just to clarify, C++ allows parameters to be specially marked so as to be passed by reference. By default, arguments are passed by value.
Few if any working Java programmers do think like that though. Like, if you have String x and String y, and println(x); prints "foo" and println(y) prints "foo" and x != y (a perfectly ordinary situation to get into in Java), we would still say "the value of x is "foo"".
Strings pretend to be immutable value objects, but they still have object identity, which doesn't really make sense as far as I can tell.
It still seems to me that the only good definition of an object variable's "value" in Java is its pointer.
Yeah. Java doesn't have proper value objects, there's these vestigal referencey effects everywhere, probably because of the language being designed for much more memory-constrained environments than those where it's actually used today. Still, most of the time you can just ignore that, remember a few simple rules like "always use .equals rather than ==" and you're good.
> It still seems to me that the only good definition of an object variable's "value" in Java is its pointer.
Good for technical pedantry maybe. Good for working programming, no - 99.9% of the time when you're talking about the "value" (not in terms of function-passing semantics, just generally) you want to talk about "foo", not about "an object reference to address 54fc892d".
> Good for technical pedantry maybe. Good for working programming, no - 99.9% of the time when you're talking about the "value" (not in terms of function-passing semantics, just generally) you want to talk about "foo", not about "an object reference to address 54fc892d".
This is almost exactly the same as pointers in just about every language that has them, though. You pass pointers around, copy them, and dereference them (which includes struct member access and array indexing), and that's about it. C is a little different because it somewhat conflates arrays with pointers to arrays, but that's hardly reason to decide that pointers are totally different. In C, you have a variable 'foo' whose type is 'T *' that when cast to an int happens to equal 0x54fc892d. The only abstraction mechanism you're asking for is the ability to store pointers in variables, it's nothing to do with their type. They're handles on objects, they're called pointers because they're values that 'point' to another value somewhere else, they're exactly what Java object variables are.
The difference is that in C you can talk about x being a char^^ value "pointer to address 54fc892d" because you can also talk about ^x being a char^ value "foo". In Java there is no ^x, so the only thing you can talk about when you want to talk about "foo" is "the value of x", and you want to talk about "foo" far more often than you want to talk about "pointer to address 54fc892d".
As an aside, C's conflation of arrays and pointers was done because they're very closely related, and you can get very similar results to a C pointer-to-pointer by wrapping an object in a one-element array. In C, ^x is equivalent to x[0], and Java doesn't have ^x, so you can just use x[0].
More generally, though, a C programmer is virtually never thinking of 'the address 54fc892d': unless they're doing really low-level stuff, they won't think of it like that any more than a Java programmer, even using pointers all day, just like the Java programmer is; that's what I don't get about your point. The C programmer will think of ^x (or alternatively x[0]) as a handle on the string "foo", the same way a good Java programmer would. Some programmers (Java or otherwise) might confuse a handle on "foo" with "foo" itself, but they'll be bitten by that when they try to write a swap function or mutate a string literal or whatever.
Java's reference types are restricted pointers that you can only dereference using . or array indexing, you can't use array indexing on any arbitrary reference (it has to be of the right type, but C pointers were already strongly typed), you can only do arithmetic on them via indexing, and you're not allowed to refer to the non-pointer type. None of those differences make them not pointers, to me.
No, I'm not talking about that at all (I guess I should've used an int rather than a string as an example, but we'd started with ints). I'm talking about the difference between char^ and char^^.
> a C programmer is virtually never thinking of 'the address 54fc892d': unless they're doing really low-level stuff, they won't think of it like that any more than a Java programmer, even using pointers all day, just like the Java programmer is; that's what I don't get about your point.
The C programmer might think of &x as a handle to x rather than a specific memory address, sure, but they can tell there's a difference between &x and x. The Java programmer doesn't have that distinction to work with.
> Java's reference types are restricted pointers that you can only dereference using . or array indexing, you can't use array indexing on any arbitrary reference (it has to be of the right type, but C pointers were already strongly typed), you can only do arithmetic on them via indexing, and you're not allowed to refer to the non-pointer type. None of those differences make them not pointers, to me.
I would say: a pointer has to point to something. Java doesn't have those because you can't get talk about "the thing the pointer points to" as a thing distinct from the pointer itself.
You get at the thing being pointed to by dereferencing the pointer. When you copy around handles to it, you can tell that you're only passing around handles, because if the object is mutable, then changes made from one handle show up in others, but your swap function still won't work. All you can do with the handle is pass it around, copy it, compare it to another handle with == or !=, dereference it, and add an index to it before dereferencing it. Dereferencing is specific to pointers, but for all the other things, they behave just like every over Java primitive does.
The effect of object variables just being pointers comes up in a lot of places, like "why doesn't my swap function work", using "==" to compare objects, initialising multiple variables to the same instance when you expected copy semantics, etc. These aren't rare things, and they're not difficult to think of. The fact that they're just pointers is the clearest explanation for all of that, and it by itself works for all of that.
Which you can't do in Java! There's no * operator.
Thinking in terms of pointers does illuminate some of Java's behaviour, sure, but it's not a reasonable way to understand the language when it requires all these concepts from C/C++ that just aren't there in Java.
> Which you can't do in Java! There's no * operator.
. and array indexing dereference pointers in Java, just as -> and array indexing do in C. I've already mentioned this several times.
> all these concepts from C/C++ that just aren't there in Java.
The Java language spec disagrees with you (before you said that explanation was pedantic; now it's incorrect?). As well, C and C++ did not invent pointers; you're the one insisting that Java's pointers aren't pointers because they don't behave identically to C's, I was saying that the specific differences don't change the fact that they're both flavours of pointer. No one is claiming that Java is source-compatible with C.
And really, there's no alternative explanation. You can learn each special case individually if you want and let your brain connect the dots to form the notion of how to use a reference without having sat down and thought about it and unified the concept, but that seems like so much work to get around learning a pretty simple idea that fully explains all of it without any special cases.
Neither of them will give you "the thing that's pointed to". And . very deliberately looks like a direct accessor in C/C++, not the dereferencing accessor ->.
> As well, C and C++ did not invent pointers; you're the one insisting that Java's pointers aren't pointers because they don't behave identically to C's, I was saying that the specific differences don't change the fact that they're both flavours of pointer.
The essence of a pointer - right there in the name - is that it's a thing that points to another thing. If the thing language has doesn't point to another thing in the language, you can't call it a pointer IMO.
> And really, there's no alternative explanation. You can learn each special case individually if you want and let your brain connect the dots to form the notion of how to use a reference without having sat down and thought about it and unified the concept, but that seems like so much work to get around learning a pretty simple idea that fully explains all of it without any special cases.
Disagree. If you learn: objects are passed by reference, == is a nonsense historical wart that you never use (as are arrays and primitves), and the default implementations of equals()/hashCode()/toString() should never be used, then you get a consistent working language that's much simpler, without having to involve anything from outside the language.
It points to a tangible thing in the language, the object that you're operating on, that thing just isn't a first class value, so you can't store it in a variable or pass it to a function. If this reasoning means that Java doesn't have pointers, then C doesn't have functions or arrays, either.
> If you learn: objects are passed by reference
They're visibly not passed by reference, though, you forgot the extra rule that using '=' on a parameter is also broken and to be avoided (from the perspective of pass by reference). So your explanation has 7 additional special rules to learn, including leaving multiple very common elements of the language at "just don't touch that", and still assumes the learner knows what a reference is anyway; why not just use the language of the Java spec and describe the actual semantics as they're defined, instead of this awkward simplifcation that takes longer to explain and involves more concepts?
> without having to involve anything from outside the language.
You also keep repeating this point even after it's been explained to be false; what language are you referring to when you keep saying Java doesn't have these concepts? The Java language spec from Oracle says:
"4.3.1. Objects
"An object is a class instance or an array.
"The reference values (often just references) are pointers to these objects, and a special null reference, which refers to no object."
They are also a part of the visible semantics of the language, as has been explained over and over in this thread, and that way you get a simple, consistent language, and it's one that people actually use instead of a made-up, more complicated subset.
Saying C doesn't have functions would be more like saying Java doesn't have objects: rather I'd say that C doesn't have pointers to functions (but has various syntactic weirdnesses to allow a function to behave like a pointer in some contexts, since the rest of the language has a value/pointer distinction).
"C doesn't have arrays, only some syntax sugar over pointers" is a common view among working C programmers. It's not a completely accurate model of the details of the language, but it can lead to fewer mistakes than not believing it (e.g. a function declaration like "int foo(int bar[5])" is actively misleading, and this is the kind of mistake someone who believes "C has arrays" may make and someone who believes "C doesn't have arrays, only some syntax sugar over pointers" won't make).
> They're visibly not passed by reference, though, you forgot the extra rule that using '=' on a parameter is also broken and to be avoided (from the perspective of pass by reference).
Point, though I think linters and IDEs warn on that one anyway.
> your explanation has 7 additional special rules to learn
Not really - you're going to have to explain the importance of not calling .equals()/.hashCode()/.toString() on random Objects either way, and you don't have to teach any extra special rules to avoid ==, != or arrays or primitives - you just don't teach any of those things.
> including leaving multiple very common elements of the language at "just don't touch that"
Any introduction to Java is going to involve a very long list of "don't touch that" (corba, dates, ejb, finalizers, monitors, AWT...), it's the nature of a language with a backwards compatibility history.
> why not just use the language of the Java spec and describe the actual semantics as they're defined, instead of this awkward simplifcation that takes longer to explain and involves more concepts?
I don't think either of those things are true. You have a bunch of extra concepts: class instances, references, and arrays - and class instances are particularly difficult to explain since they're not values in the language.
Your point was that that state of being able to have pointers to non-first-class values was a paradox, and my point was that C manages just fine (you clearly take it as an axiom that C has pointers).
> this is the kind of mistake someone who believes "C has arrays" may make and someone who believes "C doesn't have arrays, only some syntax sugar over pointers" won't make).
Sure; what are the corresponding gotchas with believing that Java has reference types? The fact that misunderstanding something in different ways will still give you problems (just believing that arrays are pointers will give you new mistakes to make, too, like with linkage and modifying string literals) isn't a very good justification for not attempting to understand it properly.
> you're going to have to explain the importance of not calling .equals()/.hashCode()/.toString() on random Objects either way
It's an obvious implication of what the default implementations do, and how they work is trivial to understand and an obvious choice for the default implementations if you know the concepts. If you understand reference types, then no further explanation is needed.
> you don't have to teach any extra special rules to avoid ==, != or arrays or primitives - you just don't teach any of those things.
You started off talking about working Java programmers in the real world, so I thought that's what we were discussing. Real-world Java programmers will see those things; you can't even write a main function without declaring an array. What about null? You can't get away with just leaving these things out, you do have to explain them as traps.
> I don't think either of those things are true. You have a bunch of extra concepts: class instances, references, and arrays
Those things you "removed" are in Java, though. Your advice was to treat them as black magic, not to actually modify the language (working programmers will see them). Knowing what features to avoid and be careful with when you can't avoid them (and presumably how to be careful with them) are things you have to learn and carry around in your head. And, as I pointed out, your version still requires people understand what references are (if you don't know what a reference is then what the hell is pass by reference passing by?). And wait then, so yours doesn't have references, primitives, arrays, or object instances? What values do you think are left in your theoretical subset?
And I disagreed with that by saying that C doesn't do that: it doesn't really have function pointers, it just allows function values to behave like pointers in some contexts.
> Real-world Java programmers will see those things; you can't even write a main function without declaring an array.
But you don't need to work with it as an array. You pass your argument array directly into an argument-parsing library and never look at it again, if your framework doesn't already do your main() for you.
> What about null?
What about it? It's a magic value that behaves like it's of every type, but throws NullPointerException when you call any methods on it. Try not to use it, try not to use libraries that use it. No pointers needed.
> And, as I pointed out, your version still requires people understand what references are (if you don't know what a reference is then what the hell is pass by reference passing by?).
You have to understand how Java passes parameters to functions (the receiver gets the same value). You don't have references as a first-class value.
> And wait then, so yours doesn't have references, primitives, arrays, or object instances? What values do you think are left in your theoretical subset?
Object values. String x = "foo" and String y = new String("foo") exist in my subset but are the same value (since I don't have object instances; x.equals(y) will be true which is the equality I care about). User-defined types exist as well, interfaces and polymorphism exist. You end up with a core language similar to, say, Python: everything is an object, objects are values rather than addresses, function parameters are passed by reference.
https://news.ycombinator.com/item?id=9246356
and
<q> Some people will say incorrectly that objects are passed "by reference." In programming language design, the term pass by reference properly means that when an argument is passed to a function, the invoked function gets a reference to the original value, not a copy of its value. If the function modifies its parameter, the value in the calling code will be changed because the argument and parameter use the same slot in memory.... The Java programming language does not pass objects by reference; it passes object references by value. Because two copies of the same reference refer to the same actual object, changes made through one reference variable are visible through the other. There is exactly one parameter passing mode -- pass by value -- and that helps keep things simple. -- James Gosling, et al., The Java Programming Language, 4th Edition </q>
Which is exactly what they are.
> But Java doesn't have first-class pointers, it has implicit pointers. The only thing you can do with a Java pointer "value" is to tacitly dereference it.
So? Just because you're not given direct access to the value itself doesn't change the semantics of the language. If you assume "pass-by" is strictly dichotomous and the choices are either value or reference, then Java can only be pass-by-value, its semantics simply don't allow the possibility of it being pass-by-ref.
IIRC the Python community calls it "pass reference by value", sadly they seem to be more or less the only ones doing so. CLU called it "pass by sharing".
> All Java "values" are (tacit) pointers to objects [1]. Pounding your fist on the table and insisting that Java is pass-by-value because you can't write a swap(x,y) function obscures this crucial difference.
Then again that Java's boxed types are boxed seems pretty obvious...
Well, there's your problem right there: pass-by is not "strictly dichotomous." There are (at least) three different argument-passing disciplines in common use. If you insist on using only two words to distinguish among them you will cause unnecessary confusion.
It's not my problem, it's yours.
> pass-by is not "strictly dichotomous."
Which you may have wanted to explain in your essay if you believe it instead of going on worthless rants.
> If you insist on using only two words to distinguish among them you will cause unnecessary confusion.
I don't.
The purpose of teaching new programmers value vs reference is to make them aware of the dangers of mutating objects passed to functions.
public static void main(String[] args) {
MyClass c = new MyClass();
c.Message = "Hello";
c.ID = 1;
mutate(c);
System.out.println(c.Message); // "Goodbye"
System.out.println(c.ID); // 2
}
public void mutate(MyClass c){
c.Message = "Goodbye";
c.ID = 2;
}
public class MyClass{
public String Message;
public Integer ID;
}Suppose we have local variables A0, B0 and A1, B1.
A0 and B0 hold references to objects O and P, respectively.
A1 and B1 also hold references to this same pair of objects, respectively.
Because Java is pass-by-value, you cannot write a function which appears swaps A0 and B0 without also appearing to swap A1 and B1 which are not passed to it. If we swap A0.content with B0.content, then there will be the unintended consequence that A1 and B1 also swap.
Swapping the referenced content isn't the same as swapping the variables; we can tell the difference because the change is not confined to just the specified variables.
Now you could argue that A0 and A1 aren't really different variables. But, undeniably, they are; even if they initially refer to the same object, they can be mutated not to. Or, if the variables are not mutated, perhaps they are initialized to the same object in some instantiations of the lexical scope and to different objects in other instantiations of the scope.
No, that's not true at all. Crucially, you can assign a new value, and that is where the distinction you're calling pedantic makes all the difference.
When assigning to a function parameter, am I assigning to the variable passed as an argument or am I assigning to a copy of that variable?
It's hard to overstate the importance of that question, and that's why these two concepts have long established names: call-by-reference and call-by value.
No, you cannot assign a new value to a pointer. You can assign a new value to a variable whose value is a pointer, and you can assign a new value to the storage location that a pointer points to (in C, though not in Java) but you cannot assign a new value to a pointer. A pointer is just a number.
I think it's obvious that I was talking about assigning to pointer variables because parameters are always variables and never just values.
> you need the distinction between call-by-value and call-by-reference to explain what happens if you assign to a parameter
You only need this distinction if:
1) Different programming languages actually handle this differently and
2) You actually assign to function parameters
If either of these conditions do not hold then you don't need the distinction. And in fact:
1) All programming languages in use today are call-by-value by default. A very small subset of them offer call-by-reference as an option. And...
2) Assigning to function parameters is never a good idea. If you're assigning to a function parameter you are almost certainly doing something wrong.
Agreed, but both conditions do hold. C++, C# and Swift support both call-by-value and call-by-reference. And the feature is actually used as most of these languages don't have (or didn't originally have) tuples or multi-valued return.
Whether or not it's a good idea to assign to reference parameters is a wholly different matter. But even bad ideas need language to explain them.
foo(int* x) takes a pointer by value. foo(int& x) takes a reference by value.
There is no such thing as a "reference object" in C++ that you could pass by value. References may be implemented using pointers under the hood and those pointers may be copied, but on a semantic level references themselves are not objects that you can copy or take the address of (contrary to pointers).
Also, at the risk of being what you are calling pedantic, dereferencing is not the only thing you can do with an object pointer in Java. You can also check nullity, equality, and cast the object. These are substantive actions with semantics that are outside any particular object's implementation.
Really, the only thing i can think of that you can't do with Java pointers that you can with other languages is pointer arithmetic - and that's due to Java's original reason for being: making portable code where object implementations could be isolated from memory allocation inner workings.
Fair enough (though checking nullity is just a special case of checking for equality).
> the only thing i can think of that you can't do with Java pointers that you can with other languages is pointer arithmetic
Well, yeah, but it's not like pointer arithmetic is some obscure little feature that is hardly ever used. Pointer arithmetic is the thing that distinguishes C-like languages from Lisp-like languages. If you're trying to explain a distinction among programming languages that involves pointers you can't just sweep pointer arithmetic under the rug as if it were a trivial detail.
That's not really convincing given many languages have pointers (as a directly manipulable concept) and actual pass-by-value but no pointer arithmetic unless you call into some sort of unsafe escape hatch.
> If you're trying to explain a distinction among programming languages that involves pointers you can't just sweep pointer arithmetic under the rug as if it were a trivial detail.
Sure you can.
Compared to C++, Java object variables behave more like pointers.
With that in mind C++ references are pretty much like references in Java or C#. The difference is that C++ additionally does not allow null references and reassignment, but that is more of a statement about the variable holding the reference than about the reference itself.
And because reference variables are readonly after initialization it may feel like C++ pointers are closer to Java or C# references than C++ references, and for practical purposes this is certainly true, but with regard to the relevant difference of references being opaque, C++ references are actually closer to Java or C# references than C++ pointers.
What about Go?
It claims to have pointers. You can't do arithmetic on them, but you can take the address of a pointer so you can do all the cute double dereference list and tree algorithms.
On the other hand Go exposes an implementation detail, the fact that references are implemented as addresses. This is probably true for most languages with references but they usually keep this an implementation detail so that it would be perfectly valid to implement references with something other then addresses.
But because you can not really take advantage of the fact that references are implemented using addresses, you can not manipulate them and it seems you can not even calculate the difference between two pointers unless you go through unsafe, I would call it references [with slightly but inconsequentially exposed implementation].
As said, this is based on a ten minute read through the first couple of search results and I probably have not even hit any official documentation, so this might very well miss something important and be wrong.
Lots of languages have it as feature, C isn't a special snowflake.
template<class T>
void swap(T& a, T& b) {
T tmp = a;
a = b;
b = tmp;
}
When called as int a=1, b=2;
swap(a, b);
The variables a and b are passed by reference, or you can think of it as an implicit pointer. This is the meaning of pass-by-reference - changes made to the value of a variable directly impact the referred-to variable.Pass-by-reference can be confusing and its inclusion in C++ is useful as immutable non-null pointers, a use which modern languages support in various other ways. Thinking of Java objects as pointers to objects might be a bit confusing at first as well, but it's the correct mental model for what's happening under the hood.
It all goes back to understanding computation in the context of a von Neumann machine with addressable random-access memory, and knowing that values are stored in numbered memory cells, so variables can be either the memory region itself, the memory region's number, which itself can be stored in a memory region whose number can be stored in another ... etc. You can't abstract away the basic properties of the computing architecture we use, so it's a good idea for programmers to have mental models of computer memory and programming language variables that are fundamentally congruent with the von Neumann architecture.
You can easily bind a C++ reference to a null pointer. Your compiler will silently accept it and the behavior will be predictably that &ref == 0 will evaluate true.
E.g.
// if OOM, &ref is null
object &ref = *new (std::nothrow) object(args, ...);
Of course, it's not defined behavior; i.e. wrong on paper.(If only a paper tiger could defend you against a real flesh-and-horn charging rhinoceros, ...)
Whether or not it's defined is moot; the fact is you can commit undefined behavior with references. They are just pointers in disguise: wolves clad in sheepskins.
References inside class/struct objects are real pointers occupying a word. If such an object is out of scope and has been deleted, and you use the reference, it's exactly the same as a use-after-free of a pointer or any other value. Through the bad reference, some wrong object will be accessed or modified.
The only relatively harmless references are the lexicaly scoped ones which go away at compile time, behaving as aliases: { int x = 42, &x_alias = x; }.
Swap is just a convenient example. Ultimately, if rebinding the function argument has no externally visible effect, it's not pass-by-reference, but rather pass-pointer-by-value — In C++ terms, a Java method with signature `foo(T arg)` is akin to C++'s `foo (T * const arg)` rather than `foo(T &arg)`.
??? Pretty sure Java is uniquivocably pass-by-value. Your example of Swap is simply incorrect.
IIRC, in a pass-by reference language, Swap could be written as
swap(int x, int y):
int z = x;
x = y;
y = z;
And then you could call it as: int a = 4;
int b = 5;
swap(a, b); // b now is 4 and a is 5
This can't be done in Java.Also Java's reference types seem to be pretty FCO to me. Just because Java don't have pointer arithmetic is hardly a disqualification.
BTW, I find it interesting that Java's argument passing semantics and Common Lisp's are, so far as I can tell, identical.
On the other hand this list is to some extent relevant to the point I was trying to make, as most of these languages are somehow related to Algol/Simula/Modula (as is C++) and not to Lisp/Smalltalk (as is Java, Python, .net...).
Object Pascal has the problem that there are at least two unrelated languages with same name. And the duffernce between Borland Pascal 7 and the Object Pascal used by Delphi is that the latter is firmly in the camp "there are only references to objects". (ie. for classes defined by 'object' keyword common pattern was "PFoo = ^TFoo", while for the 'class' ones, eg. essentially whole VCL, this is implicit)
Then there is FreePascal with its compatibility modes and own extensions.
The object keyword is still accepted in Delphi, even if they don't recommend it any longer.
Also a few languages implicitly deference pointers as references, depending on the context.
Java doesn't do "object assignment" so you cannot say
Foo d = new Foo(...);
Foo c = d;
And get two objects, you have two references to the same object. If you invoke a method on c or d it will be dispatched to the same code. So c.SetVaueX(10) and print d.GetValue(x) will show you the same value of 'x'.In C++ or other pointer languages you could have
*d = *c
which would do an assignment of the bits from one to the other, then manipulating d would manipulate its copy of the bits and manipulating c would manipulate its copy of the bits.Obviously the output will be different the input was different. The equivalent C code would have passed pointers. In that case the behavior would have been identical passed in values not swapped contents swapped. Just because Java only has object references, doesn't mean they aren't references.
If Java had pass-by-reference, you could write one that doesn't.
All values in Java are indeed either primitives or pointers. You cannot define your own values! How is anyone supposed to call this a high-level language?
It's so easy to guess their meaning consistently wrong that people don't brother to look them up. When several people wrongly guess the semantics wrong exactly the same way and talk to each other, new meaning is established.
It's not uncommon to have office debate of the difference where 9 people are sure that they know the right definition and the one person who argues for the right definition can't convince them.
EDIT: there are already at least two comments that argue that the wrong definition is the right definition. These guys feel so strongly that their definition is right that nothing convinces them and people agree. It's a hopeless pursuit to get this right.
https://stackoverflow.com/questions/373419/whats-the-differe...
I find this to be the source of most programmers' confusion about most topics. Sometimes I spend hours arguing trying to convince someone that X works one way, because I've read the spec and the source code, while they believe that X works a different way, because they looked at its name and used it that way last time.
You can't call Java pass-by-reference just because it feels right to you. It is a phrase which means something which some languages are and Java is not.
"Pass boolean by value"
"Pass integer by value"
"Pass reference-to-T by value."
The confusion arises because Java doesn't explicitly distinguish between a and &a; if you write "Foo a = new Foo();" in Java, the behaviour is similar to "Foo *a = new Foo();" in C++. So if we ask how "a" is passed, is the "a" we're talking about the reference or the value?
Seems weird to me to say that Java "passes by value" when all objects being passed are actually references to objects.
Technically yes, but since the language doesn't let you talk about references directly, the concept rarely comes up. Like, in theory you could say "a is a reference that refers to a value of type Foo", but people don't actually say that; they just say "a is of type Foo".
> Seems weird to me to say that Java "passes by value" when all objects being passed are actually references to objects.
Indeed, completely agreed.
void f(Foo x); // pass-by-value
void f(Foo* x); // pass-pointer-by-value
void f(Foo& x); // pass-by-reference
In the last example, you aren't passing in a value, you are essentially creating an alias for some variable in the calling scope.The only real difference between the last two is that the last one shouldn't be sent in as null, isn't it? The test in OPs artictle doesn't really make sense either, because you can switch the values using pointers as well.
C++ just forces you to be explicit about this, as others have pointed out.
In relational algebra a "relation" is what most people know as a "table".
"relation" is maybe a good name in the realm of relational algebra, but a bad name in the realm of users of relational databases.
In this case "pass-by-value" and "pass-by-reference" are good names in the realm of compiler theory ("I'm a compiler guy at heart") but very, very bad names in the context of discussing parameter passing in java & objects.
Sorry, i agree with your point but I felt like being pedantic :3
"Alias" means nothing to a CPU, nor is it an ABI. At the core, passing by reference is usually implemented by providing the "address-of" something to a function (for example). The "address-of" itself, is passed by value. Going by that logic, everything everywhere is passed by value.
But the language isn't defined in terms of a CPU. It's defined in terms of abstract semantic rules. You shouldn't think about implementation, especially at the CPU level, when talking about semantics.
The idea is that the alias is implicit in pass-by-reference. It isn't implicit in pass-by-value. How you implement that alias is irrelevant for discussion at this level.
I disagree. I submit the whole reason we pass objects by reference or by value in the first place, has much more to do with conserving computational resources/reducing runtime, than with providing abstract programming semantics for software developers.
(With the exception of primitives. I guess that's the real rub -- Java's special casing of primitive values.)
By the way, there is at least one additional difference in languages like Python and JavaScript with dynamic variable (not value) scope. In those languages, you can `delete` a variable, which removes the binding from the scope. Pass-by-reference would mean that you could delete a variable from a non-local scope if the variable were passed by reference. (This is not the case; `delete` in these languages merely deleted the local variable binding, as it ought, given that they are pass-by-value.)
Who died and made you secretary of the Académie anglaise? Language is defined by consensus; a word means x only to the extent that it is understood to mean x by both the sender and the receiver. This whole thread makes it pretty clear that "pass-by-reference" does not draw the distinction that you think it draws; if you want to draw those distinctions, find words that clearly draw those distinctions. Words are tools for communication, not ends in themselves.
https://courses.washington.edu/css342/zander/css332/passby.h...
I mean, it's not hard to take a look at what was already decided.
Your understanding of "what has already been decided" is contradicted by your second link. Under the definition there, Java is pass by reference except for primitives -- i.e. it is contra the "Java is Pass-by-Value" article.
(I suppose you could say that "the actual parameter" is not the referent object, but the pointer to it in the frame of the caller function. But I'm not aware of any definition of "actual parameter" that would allow you to impose that interpretation on others -- it's a vague term. I'd further argue that that interpretation is pretty convoluted, which might be why few languages other than C++ use it. Anyway, "the actual parameter" could mean the referent or the pointer to the referent depending on how you're modeling the program.)
English language usage has no bearing on technical terms, your snark notwithstanding.
C# is somewhat more clear to me because it lets you do either, which VB kinda did too.
The key point here is reference types vs value types, which is distinct from pass by reference and pass by value.
Java is pass by value only with reference types and primitive value types.
C# has reference types and value types and pass by value default with pass by reference optional.
passing a reference type by reference is passing a pointer to a pointer.
See: https://docs.microsoft.com/en-us/dotnet/csharp/programming-g...
It doesn't matter too much IMO. Most people intuitively understand how object references work in modern programming languages, and these discussions don't add a lot to their knowledge.
static void foo(Object x) {
x = null;
}
would have an effect visible to the caller. This is exactly the case with C++ references, and C and Lisp macros, which are call-by-reference. (C++, C, Lisp, and the term "call-by-reference" all having existed prior to Java, by the way, so Java and its users do not get to redefine it.)But the above function does nothing in Java. Hence, Java is not call-by-reference.
Wikipedia has a nice quote [1] from Barbara Liskov (the namesake of the Liskov substitution principle), made when she invented the passing style used in Java in 1974, for use in her language CLU:
"In particular it is not call by value because mutations of arguments performed by the called routine will be visible to the caller. And it is not call by reference because access is not given to the variables of the caller, but merely to certain objects."
She settled on the term "call-by-sharing". Maybe we should all just agree on that.
[1] https://en.wikipedia.org/wiki/Evaluation_strategy#Call_by_sh...
What makes you say this? You can't do pointer arithmetic on Java references, and the internal memory model is completely obscured. C++ and Java references look similar to and are accessed like variables. The major difference is that Java references can be reassigned, like a pointer, which is necessary in a language without true pointers.
In Java, a reference is a value, it can be stored in an ArrayList like a normal value, you can operate on the reference itself (reseating it, comparing two of them, comparing to null), there is not always a referent.
I fail to see what possible value this has.
When actually communicating with people for the purpose of conveying ideas (not just for fun), it's best to avoid terminology where not everyone has the same understanding of the definition. Open discussions about terminology are also a good way to identify these types of ambiguous terms and possibly come up with technical terms that everyone agrees on.
It is a funny language feature to have when you think about it; it just so happens to be useful. References and pointers are distinct in languages that have both (C++), so not mixing the terms between languages is helpful. If Java programmers started referring to their variables as "pointers," because internally, that's more representative of what they are, I'd be a bit irked.
It's that the phrase "pass by reference" is a term of art in compiler design, and all language theorists including those who work on Java agree on what it means, and what it means is the thing the article says it means, and Java doesn't do it.
What gets passed by value in Java? Well, sometimes it's a reference-as-Java-means-it! But that reference is always passed by value, never passed by reference.
1. The way parameters are actually passed in Java, primitives by value, object references by value.
2. How to call this mechanism.
My guess is that many fail on item 1. Once understanding of item 1 is achieved, item 2 isn't terribly interesting.
Create-copy - Copies the data into a new memory location, so modifying this variable will not modify the original variable.
Create-alias - Creates a new name for the same memory location, so modifying one variable will also modify the other variable.
Having spent too much time in Powershell, which defaults to create-copy, it was jarring to switch to Javascript and the seemingly-non-deterministic behavior of create-alias on setting a new variable equal to an array. From an algebraic perspective, when I modify "foo", I expect "bar" to remain the same.
Pass-reference-by-value is just a special case of a shallow copy.
let a = [1, 2, 3];
let b = a;
b[1] = 5; // will modify a
b = [1, 6, 3]; // will not modify a
In languages like C++, there's a way to make it so that last line _would_ modify a, which is why there's a need to use different words for the different phenomenon.In other words, "C-style" pass-by-reference means this function would have an undesirable side-effect:
void foo(Thing x){ x = null; }
Ned Batchelder - Facts and Myths about Python names and values - PyCon 2015: https://www.youtube.com/watch?v=_AEJHKGk9ns
Dog d = new Dog("fido"); d = alterDog(d);
public Dog alterDog(Dog d) { d.name="arfybark"; return d; }
It's not quite a pure function since it changes it in place, but at least the parameters and return types reflect the method. I ran across a term for this practice in the past but don't remember what it's called.
That syntax loosely implies that removing the second d assignment would allow me to create new-but-altered dogs with alterDog(Dog), which isn't the case. If I wanted to use assignments like that, I would try to go fully immutable with factory methods that help me make slightly different, new dogs on the fly, and return them.
In Java with no explicit pointers available to its users, the way objects are handled are explained better with the pass-by-reference concept than (whooosh!, magic in) pointers (and out) passed-by-value reality. Pointer is a foreign concept to Java, so it really makes more sense to its users that object variables start referring to other objects when they are reassigned, instead of the old object being changed in-place. Things get funky with equality comparison via == operator, but still, it is better than pointers.
I also wonder, does C++ really pass-by-reference when parameters have &'s behind their identifier declarations, or does it internally pass a reference by value and dereference it every time it is used within that scope? Are 4/8 bytes allocated for the reference variable or not?
I don't know what you mean by "really pass-by-reference". There is no such concept of a "reference" at the CPU level; nor is that relevant to language semantics. If you were to look at the generated assembly it would look identical to as if pointer referencing and dereferencing were used.
I was wondering if `int &a2 = a;` allocates memory in stack to make `a2` refer to `&a`, or does `a2` somehow truly become an alias for `a` in symbol table. As you've said that the assembly would look the same as pointers being dereferenced, then I suppose C++'s reference types are just a syntax sugar around the C's way of achieving the pass-by-reference concept through passing the address and then dereferencing it.
However, outside of function signatures, if you write:
int a = 2; int &aref = a; int b = aref;
I'd assume that the compiler is smart enough to optimize away &aref.
int dosomething(int * & array) {}
That * & is just complete voodoo magic.
FWIW, I don't use pass-by-value or pass-by-reference to refer to languages like Java, Python, Lua, etc... Instead, I use "pass-by-object-identity" (aka "call-by-sharing", "call-by-object") to refer to the semantics of those languages. It avoids the association many people have between the term "by-value" and copying behaviour.
Also part of the problem: many beginning and intermediate programmers don't understand the difference between rebinding and mutation. This leads to people interpreting the following snippet:
def foo(a, b):
a = 2
b.append(3)
x = 1
y = []
foo(x, y)
print(x, y) #1, [3]
... as meaning that ints are passed by value and lists by reference, while in fact both are passed by object identity, and it is the fact that a is rebound while b is mutated that made the difference.Dog someDog = new Dog("Fifi");
foo(someDog);
System.out.println(someDog.getName()); // name will be Max