DEV Community

loading...

Discussion on: A "Gotcha" of JavaScript's Pass-by-Reference

Collapse
darkwiiplayer profile image
DarkWiiPlayer • Edited

Weird. I think it's trivially obvious that javascript passes by reference. The examples kinda show that, at those developers, seem to misunderstand the definitions of call-by-reference and call-by-value rather than the nature of javascript.

The confusion seems to be about mixing up references and variable names, so maybe a better way of explaining would be translating the examples to SSA form?

It's also somewhat true that all languages are realy call-by-value, only sometimes the "value" is a reference. Just as it's true that all languages are strictly goto-based and javascript uses manual memory management and pointers. Under the hood, these all apply, it's just not a very useful way to think about it.


EDIT: Maybe people just need to use a language that is actually call-by-value like C, where they actually have to manually pass references as values to simulate call-by-reference. Seeing something for oneself is often the easiest way to understand it.


EDIT 2: So according to wikipedia, the undisputable source of truth on the internet, I am wrong, and what I call "call-by-reference" is really just "call-by-sharing", a special form of "call-by-value". So it's basically agreeing that JS is "call-by-value", with the values being references to objects.

So the real question should be:

Does call-by-reference mean a) passing references to values or b) passing references to variables?

The answer seems to differ from person to person, but the consensus might be tending towards b) from what I've seen.


EDIT 3: Thinking about it some more, I'm switching sides. Javascript is call-by-value. At first I was going at it from the perspective that objects are structs, so call-by-value would mean that mutation would return a new object. This is wrong though, objects are not structs, as they are not defined by the sum of their parts. To illustrate this:

let foo = { a: 20 }
let bar = { a: 20 }
console.log(foo == bar)
Enter fullscreen mode Exit fullscreen mode

So the "value" of an object is not just the combination of its structure and values of its members. Two objects can have the same shape and still be distinct. The "value", therefore, is the unique reference to the object. We can say it's a pointer that makes it unique, or a direct trace to the call to its constructor.

So passing the "value" of an object means passing that same memory reference, not just a copy of its data. Javascript passes objects by value.

Collapse
bytebodger profile image
Adam Nathaniel Davis Author

Weird. I think it's trivially obvious that javascript passes by reference. The examples kinda show that, at those developers, seem to misunderstand the definitions of call-by-reference and call-by-value rather than the nature of javascript.

Exactly. That's why I found it so odd when I realized that there's a (small) crowd out there that not only doesn't see this, but will argue rather belligerently against it.

The confusion seems to be about mixing up references and variable names, so maybe a better way of explaining would be translating the examples to SSA form?

Maybe. Although it's impractical to think that would ever be adopted on a grand scale.

It's also somewhat true that all languages are really call-by-value, only sometimes the "value" is a reference.

Bingo. And I do understand that JS references are saved in a value. But it's beyond confusing to try to shout everyone down by saying, "There is no pass-by-reference in JS!!!!" They can scream that all they want, but at the end of the day, the (very basic) examples illustrate that objects and scalar values are being handled very differently in memory once they're passed.

Collapse
darkwiiplayer profile image
DarkWiiPlayer • Edited

the [...] examples illustrate that objects and scalar values are being handled very differently in memory once they're passed.

Arguably. If you think about it, numbers kind of behave just like objects in assignments. They can't behave differently in mutation because they can't be mutated.

For example:

function(number, object) {
   number = 30
   object = { foo: "bar" }
}
function(40, { foo: "foo" })
Enter fullscreen mode Exit fullscreen mode

As you can see object and number both behave the same: a new value is assigned to both variables and neither is mutated and neither is changed outside the function.

Consider also this example:

function(object) {
   object.foo = 20
}
original = { foo: 10 }
reference = original
function(reference)
console.log(original == reference)
Enter fullscreen mode Exit fullscreen mode

As you can see, the variable reference still contains the same object as it did before, at least by how javascript itself defines object identity. The variable still points to the same value, but the value itself was mutated.

Additionally, consider this example of call-by-reference:

var pi : integer := 3.2; // Good enough for some people¹
...
procedure increment(var number : integer)
begin
   number := number + 1;
end;
...
increment(pi)
writeln(pi) // Lo and behold, pi is now 4.2
Enter fullscreen mode Exit fullscreen mode

If we try this in javascript, we will find that it's not possible:

let pi = 3.2
function increment(number) { number = number + 1 }
increment(pi)
console.log(pi) // As expected, pi remains 3.2 (well, our variable at least)
Enter fullscreen mode Exit fullscreen mode

Again, this comes down to how you define call-by-reference. Is the "reference" to the passed data, or to the variable from which the data is passed? Answering that core question is the only way to clarify whether JS supports call-by-reference or not.


EDIT: I haven't used pascal in a while, so I am not sure whether that program is completely correct, but it should nevertheless serve to illustrate the point.


¹ youtube.com/watch?v=bFNjA9LOPsg

Thread Thread
bytebodger profile image
Adam Nathaniel Davis Author • Edited

Excellent examples. And yeah, I've had the same kinda "aha!" moment when I realized that, in simple terms, an object is basically a mutable value. And a scalar (like: a number), is an immutable value.

This also helps to further illustrate the difference between a value, and the variable that holds that value. In most illustrations, the two concepts are interchangeable. But of course, they're not the same thing.

It took me years to really "grok" that anything (in JS, or any other language) could truly be immutable. Because I'd think of simple examples like this:

let count = 0;
count++;
console.log(count);
Enter fullscreen mode Exit fullscreen mode

My previous response would have been, "Obviously, numbers are mutable, otherwise, the 3rd line would return an error or 0." And honestly, that logic mostly "works" when trying to look at your code and determine what can be changed (mutated), and what cannot.

IMHO, this example "feels" much more like immutability:

const count = 0;
count++;
console.log(count);
Enter fullscreen mode Exit fullscreen mode

This obviously doesn't run. But of course, the error isn't spawned because the value is immutable. It's spawned because the variable itself cannot be reassigned.

Some comments have been hidden by the post's author - find out more