Hacker News new | ask | show | jobs
by Jemaclus 1312 days ago
I'm a dumb dumb. Can you define "implicit reference semantics" and "value semantics"? You use the phrases several times in your post, but I don't really understand what you mean. If it helps, I'm not a C++ programmer, but I am familiar with higher level languages like Go, Python, Ruby, PHP and Javascript.
7 comments

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)

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
“Implicit reference semantics” means that variables ordinarily refer to objects rather than containing them. “Value semantics” means that variables contain values rather than references, though there are pointer types that let you explicitly store references when you want them. (Often this is discussed in terms of parameter passing, for historical reasons, but the same ideas apply to variables more generally.)

If your language has implicit reference semantics, “x = y” will cause x and y to refer to the same object. If it has value semantics, x will be a copy of y.

Excellent, clear answer. Thank you.
Thank you
"Implicit reference semantics" = everything (or near enough) is implicitly a reference. That's what you get in Python, Ruby, or Javascript: when you pass something around, you're really passing a reference to it, a pointer. Everyone ends up referring to the same thing, and sharing it.

"Value semantics": you pass the value itself around, which means you're shallow-copying it all the time. That's what you get when you pass or return a bare non-interface type in Go.

PHP is a bit of a mess, objects are passed by reference (= implicit reference semantics) but arrays are passed by value, and you can opt them into pass-by-reference. You can also pass non-arrays by reference, though I don't think that's very common.

a = [1, 2]

b = a

b[0] = 3

print(a)

What does the above print? If the language implements reference semantics, it prints [3, 2]. If it implements value semantics, it prints [1, 2].

Thank you
Languages like Python, Java, and C# have implicit reference semantics. When you create an object, you get a pointer to that object (usually, or commonly).

In languages like C, C++, Go, Rust… references are more explicit. If you want a pointer to an object, you have to &, or something similar.

It gets a bit fuzzy.

On C#, we also have structs with value semantics, and arrays can be stack allocated.
Thank you
If you're familiar with Python and Go, you'll likely be able to quickly spot the differences in how they handle parameter passing. Python uses references and Go uses value.
Go maps and channels have reference semantics. Slices are passed and returned by value, but backing arrays are often shared (not copied) in an error-prone way, so it’s safest to pretend they have move semantics and treat only one copy as valid.

IMHO they should have used pointers everywhere they didn’t want value semantics with deep copies.

Thank you for asking - I, too, was a dumb dumb.