Pedantry matters in our profession. Details have consequences.
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
void swap(Object x, Object y) {
Object temp = x;
x = y;
y = temp;
}
is equivalent to the C program void swap(void *x, void *y)
{
void *temp = x;
x = y;
y = temp;
}
and it has the same bug for the same reason. It's only the implicit nature of references in languages like Java that makes it not look like pass by value, but that implicit nature is there in other places as well (eg, the Java code 'Object x = y' is equivalent to the C code 'void *x = y').I think the best approach is to just call it what it is, pass by value, and then also remind people if need be that objects are always pointers so it's passing a pointer by value.
I respectfully disagree. Pointers are part of the Java implementation, not part of its abstract computational model. Calling it pass-by-value when the values being passed are deliberately hidden from the user is a recipe for confusion.
Its abstract computation model is entirely equivalent to if someone did `typedef object_val *Object`, made `.` do the same thing as `->` and got rid of `->`, and then said you could only have `Object` variables, not `object_val`s. Saying that that's enough to make it not pass-by-value anymore seems ridiculous (especially when Java does still have primitives). If that were enough to make it something else, then following a style guide for C could make your code not pass-by-value anymore.
I understand what you're saying about the helpfulness to learners, but I think that they would be better served by just learning that Java classes are all reference types, their value is a reference to an object that '.' dereferences and so on, and that even if you don't want to use the word 'pointer', they happen to behave exactly like pointers. The reason I think that's better is because it also covers other common mistakes, like initializing multiple variables to the same instance and expecting copy semantics. The same mistake is being made in both that and the swap function from earlier, but the term 'pass-by-value' could only be to blame for one of them. Once you have your head around reference types, there's no problem with calling it 'pass-by-value'.
0: https://docs.oracle.com/javase/specs/jls/se8/html/jls-4.html...
Well, if so, even more reason NOT to say "Java is Pass-by-Value".
Instead, you should be a good pedant, and explain the Java passing model, its caveats and edge cases, in its entirety.
If details matter, don't throw some BS blanket statement like "Java is Pass-by-Value" around, that can be misinterpreted in 200 ways, and that doesn't capture the whole nuances of what's going on.
"Pass-by-reference" is simply wrong, as it implies behavior which Java does not exhibit.
[1] https://en.wikipedia.org/wiki/Evaluation_strategy#Call_by_sh...
Well, that doesn't apply exactly to ints and longs though...
Plus, I'd argue it's a lot easier to teach the nuances from the beginning rather than have to break someone's assumptions 4 years down the line (e.g. the traditional time of an undergrad CS education).
Of course, this kind of discussion isn't new to the Python community either. The actual calling convention is somewhere between call by value and call by reference, sometimes called "call by object". This is well worth reading: http://effbot.org/zone/call-by-object.htm
Yes it is. The thing that we talk about when we talk about "the value of foo", in Java, is passed by reference.
> Yes it is.
And this is my point in a nutshell. This argument will never be resolved, and so continuing to argue over it isn't helpful no matter how hard you pound your fist on the table.
But don't take my word for it. Pass-by-reference was understood by the person who invented the calling style used in Java (Barbara Liskov) not to apply to that calling style. [1] The argument was resolved before it could even be had, 44 years ago.
[1] https://en.wikipedia.org/wiki/Evaluation_strategy#Call_by_sh...
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."
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.