I argue with my coworkers often about it. I think the problem is that what Java calls references, works more like C/C++ pointer, rather than C++ reference. The name similarity but differing behaviour is what's confusing people.
The exception was named like that before pointers in Java were called references. Urban legend says it was Sun's marketing department demanding Java sounds less dangerous than C/C++.
People write incorrect code when they don't understand the semantics. I see this often in Python, especially surrounding its behavior with default parameters.
Pedantic arguments like this can be a good source of fun as long as everyone approaches it in a lighthearted way and acknowledges that it's pedantic. I could certainly see a conversation around pass-by-value/reference happening in my office, but if it got to the point of people getting angry at each other, that would be a sign that something is very wrong.
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.
> Java calls references, works more like C/C++ pointer, rather than C++ reference
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 C++, references aren't objects (eg. they have no size and no address), they can't be stored in a vector, there's no way to operate on the reference itself, everything is transparently forwarded to its referent, there is always a referent.
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 always just call this sort of thing "pass-by-pointer-value" to clear up any confusion. To someone coming from C++, where objects are actually passed by value, saying that Java (or Python, or what-have-you) does the same is just confusing.
Another way of saying this is "reference by value." The people who say things are pass-by-reference when they're "pass by pointer value" have likely never worked with a true pass-by-reference language, and are just taking the phrase at its English face value.
Coming from C++, if "passing by pointer value" is considered "passing by value", then what is the opposite? Not passing at all? I mean, there's always going to be _some_ kind of value being passed?
If you write foo(&a), both "you pass a by reference" and "you pass &a by value" are fair descriptions of what happens.
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?
Ah, I see the reasoning. I only did basic Java in university so I might be remembering incorrectly, but aren't variables storing non-primitive values called "References"?
Seems weird to me to say that Java "passes by value" when all objects being passed are actually references to objects.
> I only did basic Java in university so I might be remembering incorrectly, but aren't variables storing non-primitive values called "References"?
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.
But it's still just a pointer underneath? It's more or less just syntactical sugar which makes it dereferenced it for you, and I'd argue that it only makes sense to use the phrase in certain contexts.
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.
My made-up term "pass-by-pointer-value" just emphasizes the fact that in Java, Python, and sundry other OOP languages, you are always passing around a pointer to an object, even if it is implicit. This is why e.g. equality usually checks object identity (pointer value) in these languages (Python being a notable exception).
C++ just forces you to be explicit about this, as others have pointed out.
Yes. This is what lmm and others in this thread are missing. Pass-by-reference includes behavior which Java does not exhibit but which several other languages (C++, C and Lisp macros, etc.) do.
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.
This comes up once every few years. The confusion comes from the fact that java syntactically hides the pointer for objects, which feel kind of like structs.
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.
These terms are so frustrating because they have "consistently wrong intuitive semantics" (I don't know better term). They are like cognitive puns.
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.
> It's so easy to guess their meaning consistently wrong that people don't brother to look them up.
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.
> "Pass-by-reference: The formal parameter merely acts as an alias for the actual parameter."
"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.
This is the answer. Under the definition proposed in the article, all languages where the "=" operator can copy the values inside referents are "pass-by-reference." Languages where the "=" operator lacks that capability are pass by value. That is the only difference between swap in java and c++. In C++, operator= is a method over the value of the referent. In Java, you have to explicitly call that method. IMO it is a useless definition of "pass-by-reference," but the author is entitled to it.
(With the exception of primitives. I guess that's the real rub -- Java's special casing of primitive values.)
It is literally the definition of pass-by-reference. Your opinion does not change it.
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.)
> It is literally the definition of pass-by-reference. Your opinion does not change it.
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.
> In pass by reference (also called pass by address), a copy of the address of the actual parameter is stored. Use pass by reference when you are changing the parameter passed in by the client program.
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.)
No. If Java were pass-by-reference a function could cause the caller's reference to point to an entirely different object. That is, yes, the implementation must pass a pointer which points into the caller's frame. This is what happens with C++ references. This is not what happens with Java arguments.
I've been working in the field of language translation in and out of academia for over a decade. I think that makes me pretty qualified to communicate the definition as used in standard literature.
English language usage has no bearing on technical terms, your snark notwithstanding.
> "Alias" means nothing to a CPU, nor is it an ABI.
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.
> "But the language isn't defined in terms of a CPU."
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.
I was looking for some kind of indicator when this article was written as the topic and style of design could be from the 90’s and the copyright goes from 1996 to 2014
This article is overly pedantic. Java's semantics are pass-by-value only of you consider that the "values" that are being passed are pointers. 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.
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.
But Java isn't pass-by-reference. Saying so is simply wrong, for exactly the reasons you write off as "pedantry". I see this play out all the time with co-workers who are new to Python (which has the same semantics) being very confused about why "numbers are passed by value but objects are passed by reference".
Pedantry matters in our profession. Details have consequences.
Personally, I'd argue there's only one concept -- pass-by-value -- with a whole lot of language-specific syntactic sugar as to what is getting passed by value. But I'll call myself out on that being even more pedantic than the current discussion.
I've heard this term "unityped", but i'd always written it off as a politically correct way of saying "untyped". Is there actually a worthwhile argument for it?
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.
Untyped languages actually allow you to perform any operation on any value and will always do something sensible. The sensible thing to do is to throw an exception in most cases.
The difference between safe dynamically typed and untyped is whether the throw will happen or not. There are degrees of safety even in dynamically typed languages.
I think the argument is that when every value inhabits the sole type and everything accepts that type, you get a system that works the way "untyped" languages do. Why have two separate concepts when you can gain some true conclusions by unifying?
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.
To a first approximation, a type is an equivalence class of expressions such that the set of valid programs is closed under substitution of one of these expressions for any other (compare with the definition of a part of speech in grammar). In a typical dynamic language, anywhere the syntax requires an expression, any expression will do, so there is only one equivalence class.
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.
>I've heard this term "unityped", but i'd always written it off as a politically correct way of saying "untyped". Is there actually a worthwhile argument for it?
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).
By forcing "pass-by-reference" to mean two things you are creating ambiguity that is trivially resolved by correctly interpreting a java type signature.
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 think there is value in actually having a term for Java's (and Python's, and Ruby's, and Javascript's) argument-passing semantics, what was called "call by sharing" in CLU (and sometimes called pass-reference-by-value in some communities), because it's sufficiently different than either pass-by-reference or "full-fledged" pass-by-value that using these terms gets confusing, especially to people not learning them… which would be those you're using these with as the others have no issue understanding them.
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.
There cannot be a real meaning or a right meaning, only an agreed upon meaning. And the rest of the world first have to agree on that meaning. But there is no agreement so far.
Furthermore, the term is so useless, that most people only encounter it in debates about its meaning.
There can be an original meaning. The idea of hiding pointers and not allowing them to be reasoned about separate from the objects they point to is a relatively new invention. The terms "pass by value" and "pass by reference" predate that invention.
There is a real and exact meaning in programming language semantics. It's used consistently in language specs and literature.
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.
What you say is true ONLY within a specific context. Your statement is never true in the "world" or "universe".
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.
If I correctly understand what you are referring to, then there are four variants, not three. And those four variants are the product of two orthogonal binary choices and we have names for all of them. There are value types and references types and you can pass each of them by value or by reference for a total of four variants. There are of course actually even more variants, but they are not really relevant for the discussion at hand.
> those four variants are the product of two orthogonal binary choices and we have names for all of them
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.
> The real problem here is that we have only two terms which we're using to try to distinguish between three different concepts.
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 think the best approach is to just call it what it is, pass 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.
> 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'.
Additionally, the Java language spec[0] does use the word pointer: "The reference values (often just references) are pointers to these objects, and a special null reference, which refers to no object." That isn't an implementation note, it's the language the spec uses to describe how reference values relate to object instances.
I'll second this. As someone who spends most of their time flipping between C and Python, the details of how parameters get passed between functions is intimately related to each language, and keeping it all clear meant having to understand the nuances.
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).
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.
The argument is resolved pretty simply by considering that the term "pass-by-reference" was defined well before Java even existed, and that Java does not exhibit behavior required of that calling style. (In Java, you cannot change a variable in the caller's scope to point to a different object.) Java is demonstrably not pass-by-reference.
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.
> You might think that the value of foo is that which is compared when evaluating foo == bar
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"".
Equality on strings is a common source of confusion in Java, and I think that's because many newbies aren't properly taught the kind of semantic pedantry we're discussing... and because the language design is weird.
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.
> 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.
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".
> > 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".
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".
Well, that's just the little difference I mentioned about C conflating arrays and pointers to them. The char ^ is being viewed as an array, which in C happens to be synonymous with a pointer to the start of the array. It's certainly not inherent to pointers that they be mixed up with arrays like that (or to strings that they be represented as char arrays).
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.
> Well, that's just the little difference I mentioned about C conflating arrays and pointers to them.
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.
> 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.
> You get at the thing being pointed to by dereferencing the pointer.
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.
> > You get at the thing being pointed to by dereferencing the pointer.
> 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.
> . and array indexing dereference pointers in Java
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.
> If the thing language has doesn't point to another thing in the language, you can't call it a pointer
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.
> If this reasoning means that Java doesn't have pointers, then C doesn't have functions or arrays, either.
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.
> Saying C doesn't have functions would be more like saying Java doesn't have objects
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?
> 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).
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.
<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>
The answer Gosling actually gives in your link is "Depends on your terminology"; he acknowledges it "behaves like pass-by-reference". You say "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" - but this is the behavior of Java. Gosling talks about "the pointer" because he's thinking in terms of the implementation, but that can't be the correct answer in the context of Java because pointers don't exist in the language.
No, it is not. Prove it to me by writing a Java function which can cause a variable in the caller's scope to point to a different object. You cannot, because Java is not pass-by-reference. C++ is, and you can do this. So are macros in many languages, and you can do this. Java is not pass-by-reference.
> Prove it to me by writing a Java function which can cause a variable in the caller's scope to point to a different object.
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.
Coining a new term is the right approach if you want to draw that distinction. "Java is call by sharing" would be fine. "Java is call by value" is more wrong than "Java is call by reference".
I don't know, "'Java is call by sharing' would be fine" looks pretty similar to my first comment on this story [1]. I thought we were on the same page.
I suggest you re-read the Hacker News guidelines [2] for what constitutes acceptable discourse on this site. Your first comment to me [3] and your most recent comment demonstrate a lack of civility on your part.
> I don't know, "'Java is call by sharing' would be fine" looks pretty similar to my first comment on this story [1]. I thought we were on the same page.
On that much we are. But if we are reducing it to a dichotomy of "call by reference" versus "call by value", as the original article does (which is a simplified model of the space of possibilities, but legitimate; all models are false, some are useful), then "java is call by reference" is the true statement, because java's behaviour is within the sphere of "call by reference" behaviours and very much distinct from the sphere of "call by value" behaviours.
> I suggest you re-read the Hacker News guidelines [2] for what constitutes acceptable discourse on this site. Your first comment to me [3] and your most recent comment demonstrate a lack of civility on your part.
You first; I've been matching your tone when replying to you, that's all.
Perhaps you should actually read up what the terms mean then, because the challenge they gave you (pretty much implementing a swap) is perhaps the quintessential explanation of the difference between pass by reference and pass by value.
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.
>Pedantry matters in our profession. Details have consequences.
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.
As I said elsewhere in this thread, personally I use the term "pass-by-pointer-value". Barbara Liskov used the term "pass-by-sharing" (actually "call-by-sharing") when she invented the damn thing in 1974. [1]
"Pass-by-reference" is simply wrong, as it implies behavior which Java does not exhibit.
OK, but in Python this isn't actually true... numbers are not passed any differently than other kinds of objects. As such, it does not have the same semantics as Java, which does distinguish between primitives and non-primitives.
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
No, Java makes no such distinction in passing. Java does have values which are not object pointers, but, just like object pointers, they are passed by value, and behave exactly the same as an immutable object in either language.
> This article is overly pedantic. Java's semantics are pass-by-value only of you consider that the "values" that are being passed are pointers.
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...
> If you assume "pass-by" is strictly dichotomous and the choices are either value or reference
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.
Disagree - the distinctions you are talking about (no pointer arithmetic) has much less to do with "pass by value" than the OPs points.
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.
> You can also check nullity, equality, and cast the object
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.
> 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.
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.
That is why the article is wrong when it says that Java has pointers. It does not, it has references. C#, for example, has pointers and references and they are not the same.
References are opaque handles for values, you can just deference them and compare them for equality. Pointers are not opaque, their values are address and you can perform arithmetic on them.
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.
> References are opaque handles for values, you can just deference them and compare them for equality. Pointers are not opaque, their values are address and you can perform arithmetic on them.
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.
I never used Go in any meaningful way so I just had to look at the documentation. I lean towards classifying it as references instead of pointers despite the name. References to references are perfectly valid even though they are not available in all languages with references.
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.
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.
C also has only pass-by-value semantics. The difference is that you can take the address of a variable, i.e. you can stack as many layers of references as you want. In case of the C++ swap:
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.
> Pass-by-reference can be confusing and its inclusion in C++ is useful as immutable non-null pointers
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; }.
>The only thing you can do with a Java pointer "value" is to tacitly dereference it.
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.
You're ignoring my point, which is that you need the distinction between call-by-value and call-by-reference to explain what happens if you assign to a parameter.
I think it's obvious that I was talking about assigning to pointer variables because parameters are always variables and never just values.
I'm not ignoring your point. I'm saying that your point is not a point worth making, at least not in the context of talking about relevant distinctions among different programming languages.
> 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.
>If either of these conditions do not hold then you don't need the distinction.
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.
That's nitpicking. Pass-by-reference is defined by its semantics, not by an implementation that avoids copying anything.
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).
Why not? Java support reflection, so you can - at runtime - enumerate all the properties of an object. From there, you would assign each property from a to b. The only thing stopping this is that not all properties will be public, but this seems like a pedantic hangup to me. They are functionally equivalent.
I believe the author was being as pedantic as they were in order to avoid having the discussion you just brought up.
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.
> Java's semantics are pass-by-value only of you consider that the "values" that are being passed are pointers.
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?
That notable exception exists at least in Object Pascal, Oberon, Oberon-2, Active Oberon, Component Pascal, Modula-2, Modula-3, Ada, Eiffel, Sather, D, Swift.
I probably should have qualified that with "widely used". :)
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)
Actually there a few unrelated Object Pascal languages, the language features from Turbo Pascal, introduced on version 5.5 for MS-DOS, were copied from Apple's Object Pascal.
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.
Your propositions is wrong here in the following way.
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.
> 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.
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)`.
TFA is overly pedantic, but your swap() method is not generic and falls apart if the class has more than one instance variable. In Lisp, for example, it's trivial to write a swap macro -- not very fair, I suppose. In Tcl you can have a proper swap that is not a macro (which is good, since Tcl does not have macros!) by using Tcl's pass-by-name semantics. In C++ you can just declare the arguments as references and then you won't notice at the call site that the arguments are being passed by reference -- super convenient, but then somewhat scary as well. And so on.
This is similar to relational algebra & relational databases.
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.
A relation can't have multiple identical rows, but a table in most databases can, of course no primary key works for such a set of data and you can embed such a table into another table which has an underlying relation.
Sorry, i agree with your point but I felt like being pedantic :3
Reference values are part of the Java language. It's the reason "==" doesn't do what you'd expect it to, and why "a = ..." inside a method (assuming "a" was a parameter) doesn't affect the caller.
While C++ is a whole lot of different language with operator overloading amd everything, I don't think the pass-by-reference in the C++'s way with &'s before the variable/parameter identifiers is much different from how Java handles the objects behind the curtains.
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?
No, it really is different. In C++ you can assign to variable references without additional syntax. You cannot do this (at all) in Java.
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 don't know what you mean by "really pass-by-reference".
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.
I don’t see why C++ “references” should have a monopoly on the term “reference," such that a language calling anything else a reference is making an error. C++ references are actually kind of a weird/unusual language feature that isn’t being taken up by other languages. I don’t see cause for reserving a term for them. Each language can decide what it is going to call a “reference.”
Java references are closer to C++ references than anything else. They're like pointers until you access/call them, at which point they're just objects. C++ references are identical, but the syntax is a bit more explicit.
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 not that other languages don't have references, or that they cannot redefine references.
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.
The fact that so many people get this wrong yet are so sure they're right is indicative of a U/X issue. Fix the nomenclature and you'll fix the problem.
It's not really a UX problem as these things are not actually used. We just can't agree with each other what the nomenclature should be and it's this way precisely because there is no real use for the nomenclature.
That, and I don't think there is a real consensus on the nomenclature, even in the literature. At least, I don't remember university lectures being at all clear on the issue.
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.
"Create-copy" and "create-alias" are better ways to describe the concepts. This post describes pass-by-value as create-copy, and pass-by-reference as create-alias.
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.
The confusion comes up when you do a _shallow_ copy: Some modifications will modify the original variable, and other modifications won't.
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.
This is a problem in PHP, which has both primitives (including copy-on-write arrays) and Java-style objects, but it also has literal pass-by-reference referencing (you can write a swap function). The misuse of “pass-by-reference” here creates confusion.
I thought this was common knowledge. I was taught that Java is pass-by-value in compiler-writer terms, but as a programmer you can think of it as pass-by-reference because you have no control over it.
I believe the difficulty with "pass by reference" is that the phrase implies (at least in other languages) that the function-body can potentially alter variables in the caller's scope, by assigning something to the parameters it is given.
In other words, "C-style" pass-by-reference means this function would have an undesirable side-effect:
Is it bad to completely ignore this behavior? For instance, something like:
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.
I would actively avoid that, but only because it confuses me.
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.
There's a lot of confusion in this thread about what "call-by-reference" means. Let's be very clear. If Java were "call-by-reference", then this function:
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.
198 comments
[ 3.3 ms ] story [ 284 ms ] threadI 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.
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.
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.
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.
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."
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.
Dog someDog = new Dog("Fifi");
foo(someDog);
System.out.println(someDog.getName()); // name will be Max
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.
"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.
(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.
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.
In fact, you can write a swap(x,y) function in Java. It goes something like this:
(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:
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.
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.
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.
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.
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
is equivalent to the C program 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...
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).
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...
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>
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."
Wait, no, not glad. That's really tragic. I hope you're ok.
I suggest you re-read the Hacker News guidelines [2] for what constitutes acceptable discourse on this site. Your first comment to me [3] and your most recent comment demonstrate a lack of civility on your part.
[1] https://news.ycombinator.com/item?id=16896221
[2] https://news.ycombinator.com/newsguidelines.html
[3] https://news.ycombinator.com/item?id=16896569
On that much we are. But if we are reducing it to a dichotomy of "call by reference" versus "call by value", as the original article does (which is a simplified model of the space of possibilities, but legitimate; all models are false, some are useful), then "java is call by reference" is the true statement, because java's behaviour is within the sphere of "call by reference" behaviours and very much distinct from the sphere of "call by value" behaviours.
> I suggest you re-read the Hacker News guidelines [2] for what constitutes acceptable discourse on this site. Your first comment to me [3] and your most recent comment demonstrate a lack of civility on your part.
You first; I've been matching your tone when replying to you, that's all.
Please try to be more civil in the future.
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.
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...
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
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.
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.
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.
The purpose of teaching new programmers value vs reference is to make them aware of the dangers of mutating objects passed to functions.
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.
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; }.
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).
Java doesn't do "object assignment" so you cannot say
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
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.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?
??? 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
And then you could call it as: 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.
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.
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)`.
If Java had pass-by-reference, you could write one that doesn't.
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
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.
Ned Batchelder - Facts and Myths about Python names and values - PyCon 2015: https://www.youtube.com/watch?v=_AEJHKGk9ns
Article: https://nedbatchelder.com/text/names.html
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.
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.
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...
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:
... 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.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.
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; }
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.
int dosomething(int * & array) {}
That * & is just complete voodoo magic.
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...