5 ms·
I wonder how comparable the situation is to jq, which also does CoW / immutable data. In jq, when a datum has only one live reference, changes to that datum ac
by cryptonector 8y ago
I wonder how comparable the situation is to jq, which also does CoW / immutable data. In jq, when a datum has only one live reference, changes to that datum actually mutate the datum. A C example is probably necessary to make this clear:
jv v = jv_array(); // ref count == 1
v = jv_array_append(v, jv_number(0)); // Ostensibly copy
v = jv_array_append(v, jv_number(1)); // but actually mutate
Here, in all cases there is exactly one reference to the array `v`, so `jv_array_append()` actually modifies it in place. Do note that `jv_array_append()` returns a new `jv` value though, and that this is necessary to support the copy-on-write case:
jv v = jv_array(); // ref count == 1
jv v2 = jv_copy(v); // ref count == 2 now!
v = jv_array_append(v, jv_number(0)); // Copy!
// Now `v`'s ref count == 1 again (and so does `v2`'s!)
v = jv_array_append(v, jv_number(1)); // Ostensibly copy, actually mutate
You can imagine similar mechanics in an ECMAScript implementation.
Note that in jq itself this is mostly not something a user ever has to think about because one is always passing modified structures to an expression on the right:
(.foo = "bar") | ... # this sees .foo == "bar"
but it can be user-visible anyways:
((.foo = "bar") | ...), # ... sees .foo == "bar"
.foo # but here .foo is as it was before
Here the last reference to `.foo` happens outside the lexical context of the assignment to `.foo`, so the assignment is not visible. Under the covers this all is made possible by the C jv API's copy-on-write design where functions always consume a reference to their input `jv` values (except `jv_copy()`, `jv_get_kind()`, `jv_string_value()`, and `jv_number_value()`) and return a new `jv` value to replace the one that was "modified".