getify/You-Dont-Know-JS

Values vs References semantics

Closed this issue · 5 comments

https://github.com/getify/You-Dont-Know-JS/blob/master/types%20%26%20grammar/ch2.md#value-vs-reference

I don't want to nit pick, but your argument for values and references here is flawed.
You're asserting that javascript has no pointers, primitives are passed by value, and object/function/symbol are passed by reference.

I would contend that javascript has pointers (though they can't be accessed directly) and everything is passed by value all the time every time with object/function/symbol having their pointer (which you're conflating to being the same as a c++ reference) being passed by value (in reality primitives work this way as well because there really aren't primitives in Javascript, but that's another matter).

This is a tricky matter that has some expensive memory consequences.

This code:

var a = {};
var b = a;

actually is 2 pointers to the same heap memory and has to allocate the object memory and two pointers (one for a and one for b).

Similarly:

function foo(b) {}
var a = {};
foo(a);

makes a copy of the a pointer and passes it to foo. (so same deal memory wise, there's the object memory and 2 pointers).

If it were passing by reference there would be no memory costs associated with passing objects, but because it is passing a copy of a pointer by value, there are memory costs associated with pointer copying...

This method of passing by value isn't specific to JS but is exactly the same in C and Java.

Here's the relevant V8 docs describing function calls with values.
http://izs.me/v8-docs/classv8_1_1Function.html
http://izs.me/v8-docs/classv8_1_1Handle.html
http://izs.me/v8-docs/classv8_1_1Value.html

Function calls are made using an array of handle objects which are wrappers around pointers to a Value object (which Object/Function/Primitive inherit from).

I'm not saying that the description of how everything works is wrong, but I take issue the terminology.
References are never in play here, just pointers which you don't have access to.

I think you may be coming at the topic from a different perspective, more based on the underlying implementation details. My perspective in explanation is the observable aesthetics in the language.

Here's a very complete (and I might say, pretty authoritative) explanation:

http://docstore.mik.ua/orelly/webprog/jscript/ch11_02.htm

In particular, this paragraph speaks to what I think may be our difference in perspective on terminology:

Before we leave the topic of manipulating objects and arrays by reference, we need to clear up a point of nomenclature. The phrase "pass by reference" can have several meanings. To some readers, the phrase refers to a function invocation technique that allows a function to assign new values to its arguments and to have those modified values visible outside the function. This is not the way the term is used in this book. Here, we mean simply that a reference to an object or array -- not the object itself -- is passed to a function. A function can use the reference to modify properties of the object or elements of the array. But if the function overwrites the reference with a reference to a new object or array, that modification is not visible outside of the function. Readers familiar with the other meaning of this term may prefer to say that objects and arrays are passed by value, but the value that is passed is actually a reference rather than the object itself.

Note: References in C++ are actually pointers, but just with the de-referencing syntax hidden. Perhaps that's also part of the difference in our perspective.

In any case, I believe it's well established that "reference" is the proper terminology for what's going on in JS, and after re-reading, I believe I've been true to that precedent in my use of the term.

While I agree that there's kinda sorta standard terminology around saying "a reference to the object is passed to the function", saying that Javascript is "pass (call) by reference" is just incorrect.

Just as pass by value means copying of memory is occuring, pass by reference has specific connotations as well (ie, no memory allocation, direct memory access). Javascript does not exhibit the eval semantics that pass by reference demands. In fact it is very observable to see the effects of memory allocations happening whenever arguments are passed to functions (ie new pointers have to be created) which indicate that every call is copying and passing pointers.

Furthermore, I'm kinda inclined to listen to what Brendon Eich has to say on the matter... https://groups.google.com/forum/#!msg/netscape.public.mozilla.jseng/bSNJUWKg1mI/NBc8-e71lX8J
He specifically references the fact that what's going on is copying pointers around.

I know that this is really digging into implementation details, but with the way the ES spec is setup, there's no way to implement the language except passing pointers by value around.

I think this fact needs to be made clear as there's still a kajillion posts all over the internet asking "is Javascript pass by value or reference" partly due to ignoring the underlying implementation details of what is happening which are very clear on what is happening (terminology aside).

Now all that being said, I'd be cool with saying "a copy of a reference to an object is being assigned or passed to a function". This is an accurate portrayal of what is happening and clearly demonstrates the pass by value semantics of what is going in Javascript.

Another option would be to provide a really nice definition of what is happening to break from the confusion. Probably a better term (and one that a bunch of people have started throwing around) is "call by sharing". This is referenced in detail here: http://dmitrysoshnikov.com/ecmascript/chapter-8-evaluation-strategy/ and http://en.wikipedia.org/wiki/Evaluation_strategy

Overall I think we'll continue to disagree on this, but like you said, this is a confusing matter but it doesn't have to be if things are properly laid out.

I think the hang up for me are the following lines which have the "pass by reference" copy built into them:


Complex values (aka compound primitives) are always assigned/passed by reference:

Would rather see:

Complex values (aka compound primitives) always create a new reference on assignment and a copy of the reference is passed into function calls:


When we pass in the argument a, it assigns x by reference to point at the [1,2,3] value.

Would rather see:

When we pass in the argument a, it assigns a copy of the a reference to x. x and a are both pointing to the [1,2,3] value.


It may occur to you that if you wanted to pass by reference a scalar primitive value like 2, you could box the value in its Number object wrapper. It is true that such an object value would instead be passed by reference.

Would rather see

It may occur to you that if you wanted to pass a reference to a scalar primitive value like 2, you could box the value in its Number object wrapper.


Here, obj acts as a pass-by-reference wrapper for the scalar primitive property a, so that the property's value can be updated in a persistent way that survives the end of the function call.

Would rather see:

Here, obj acts as a wrapper for the scalar primitive property a, so that the property's value can be updated in a persistent way that survives the end of the function call.


I think with those changes, the clarity of that section will increase dramatically.
Thoughts?

I think your suggested changes are consistent with what I'm already saying. If they give a nod to accuracy of how the implementation works, but still honor the precedent of how JS is typically explained (as compared to other languages), I think that's a net positive.

So, I'll make some changes as suggested. Thanks! :)