Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

let binding record and tuple should be writable #372

Open
magic-akari opened this issue Apr 3, 2023 · 6 comments
Open

let binding record and tuple should be writable #372

magic-akari opened this issue Apr 3, 2023 · 6 comments

Comments

@magic-akari
Copy link

magic-akari commented Apr 3, 2023

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

@acutmore
Copy link
Collaborator

acutmore commented Apr 3, 2023

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
Copy link
Collaborator

acutmore commented Apr 3, 2023

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

@phryneas
Copy link
Member

phryneas commented Apr 3, 2023

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.

@magic-akari
Copy link
Author

magic-akari commented Apr 3, 2023

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.
tc39/proposal-deep-path-properties-for-record#19 (comment)

@mhofman
Copy link
Member

mhofman commented Apr 3, 2023

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.

@hax
Copy link
Member

hax commented Apr 16, 2023

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 tc39/proposal-deep-path-properties-for-record#19 (comment), but I change -> to |. which still contains . in the syntax)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants