proposal-record-tuple icon indicating copy to clipboard operation
proposal-record-tuple copied to clipboard

`let` binding record and tuple should be writable

Open magic-akari opened this issue 2 years ago • 6 comments

As a JavaScript developer, I expect to see arrays and objects like primitive value, rather than ones that are completely not writable. I expect modifying a partial value in tuple/record should update the whole value of tuple/record.

const foo = #[1, 2, 3];

let bar = foo;

console.log(foo === bar); // true
bar[1] = 5; // It's `let` binding. I think this is OK

console.log(foo === bar); // false

bar[1] = 2; // change back
console.log(foo === bar); // true

foo[1] = 5; // expect runtime error, foo is `const` binding!!!

/* It' similar to primitive value */
/* Think the above code as following */

const a = 1;

let b = a;

console.log(a === b); // true
b = 5;
console.log(a === b); // false
b = 1;
console.log(a === b); // true

a = 5; // runtime error!!!

code

magic-akari avatar Apr 03 '23 08:04 magic-akari

Hi @magic-akari

Unless I have misunderstood the issue, this sounds like you might have mixed up two unrelated concepts in JavaScript.

let and const create a "binding" from a name to a value in their enclosing scope. The binding does not impact the value it "references".

Records and Tuples are new types of value, their semantics are encoded internally to the value. If they are accessed via let this would not change how they behave. A language could have those semantics but that would at least be out of scope for this proposal.

acutmore avatar Apr 03 '23 08:04 acutmore

Here's an example of how strings (a primitive list vaguely similar to Tuples) currently behave with let:

const isPrimitive = (v) => Object(v) !== v;
assert(isPrimitive("strings"));

const a = "test";
let b = a;
assert(a === b);
b[0] = "T"; // TypeError strings are immutable

acutmore avatar Apr 03 '23 08:04 acutmore

Adding to that, if you request this because deep updates seem complicated to you, please take a look at the deep spread syntax for Records proposal.

phryneas avatar Apr 03 '23 12:04 phryneas

Adding to that, if you request this because deep updates seem complicated to you, please take a look at the deep spread syntax for Records proposal.

Thanks for your reply. What I'm looking forward to is the idea mentioned in this comment. https://github.com/tc39/proposal-deep-path-properties-for-record/issues/19#issuecomment-1013627879

magic-akari avatar Apr 03 '23 13:04 magic-akari

As @acutmore mentions, this really would be a change to the semantics of the language that is not specific to records and tuples. Strings are also composite primitive values (a list of codepoints), and if we allow updating individual entries in a tuple the way suggested, there is no reason updating a string shouldn't work similarly.

That is a much deeper change to the language which basically boils down to saying that an assignment to a reference may in some case not mutate the value behind the reference, but the value of the base part of the reference. The main problem I see is that there is no way to differentiate from just the reference which case it is, as it depends on the type of the value behind the reference. Having an explicit way of doing this kind of deep assignment seem more appropriate.

mhofman avatar Apr 03 '23 13:04 mhofman

Having an explicit way of doing this kind of deep assignment seem more appropriate.

It seems Swift do not use explicit way but not cause confusion. So maybe it's not a big deal. Of coz, Swift is designed to have both value types (structs) and reference types (classes) from the start, JS has different history, we might be conservative on such change. Anyway, I think having an explicit way is a good tradeoff. Possible explicit syntax would be:

const foo1 = #{ bar: #{ baz: 123 }  };
let foo2 = foo1;
foo2|.bar.baz = 456;
assert(foo1.bar.baz === 123);
assert(foo1 !=== foo2);

(Copy @mhofman 's idea from https://github.com/tc39/proposal-deep-path-properties-for-record/issues/19#issuecomment-1494380186, but I change -> to |. which still contains . in the syntax)

hax avatar Apr 16 '23 06:04 hax