Hacker News new | ask | show | jobs
by TheRealPomax 1317 days ago
It's the difference between assigning/passing around "copies of the data" vs. assigning/passing around "the memory address for that data" under the hood.

PHP, for example, has explicit references. If you have an `$arr1=array(1,2,3)` and an `$arr2 = $arr1`, that second array is a full copy of the first array, and updating $arr1 does nothing to $arr2. Similarly, `function update_array($arr) { $arr[0] = 'cake'; }` called with `$arr1` will create a copy of $arr1 for use inside that function. Any changes to `$arr` inside the function only apply to that copy, not to $arr1. Unless you explicitly tell PHP you want to work with references, by using `function update_array(&$arr) { ... }` instead. PHP uses value semantics.

JS, on the other hand, uses implicit reference semantics. If you have a `const arr1 = [1,2,3];` then `arr1` is an alias, simply pointing to a memory location, and declaring a `const arr2 = arr1`, makes arr2 also be an alias for that same memory location. They both reference the same thing, but neither "is" the thing. Similarly, if you have a `function updateArray(arr) { arr[0] = 'cake'; }` then that `arr` is also just an alias pointing to the memory location of whatever you passed in, and changes to `arr` change the underlying data, so whether you try to access that through `arr1`, `arr2` and `arr`, it's the same thing. JS uses implicit reference semantics.

(But note that many languages with implicit reference semantics make exceptions for immutable primitives like numbers or strings)

3 comments

That's not technically correct with regards to PHP. Your statement that any changes to $arr1 or $arr2 only impact the one in question, however, is accurate. If no changes are made they still refer to the same data in memory. It's copy-on-write semantics.

$arr1 = [1,2,3]; // $arr1 is a pointer to a zval array [1,2,3] and refcount:1

$arr2 = $arr1; // $arr1 and $arr2 are pointers to the same zval array but incremented refcount to 2.

$arr2[] = 4; // at this point, $arr2 creates a new zval array, copies over the data from the first, sets the recount to 1, and appends int(4). The [1,2,3] array has its refcount decremented to 1 as it's still referenced by $arr1.

[1] http://hengrui-li.blogspot.com/2011/08/php-copy-on-write-how...

Actually that is outdated since at least PHP 7. In modern PHP the engine uses copy on write only for "larger" things, but "small" things like integers or booleans live on the stack and are copied around, avoiding heap allocations etc.
This isn't semantics, though, but implementation. As far as I'm aware there's no way to "observe" the copy short of digging into runtime debugging tools, so I think it's still fair to say the language has pass-by-value semantics. In C++ we still refer to things returned-by-value as returned by value despite the reality of NRVO, etc.
> It's copy-on-write semantics.

CoW is not semantics, it’s a way of implementing value semantics which avoids unnecessary defensive copies.

true, good point.
PHP has implicit references too, objects are passed by reference by default (primitives by value, like your note)
Thank you