-
Notifications
You must be signed in to change notification settings - Fork 61
Should with
even be a part of this proposal?
#41
Comments
I feel like having the two together is a good idea; otherwise, you might end up with a situation where, despite immutable data structures existing in the runtime, people are using good ol fashioned pretend-immutable data structures with libraries like Immer for the better developer ergonomics when making deep changes instead. But, I do also feel like having something akin to Immer built in to JS is a great idea on its own too, and this repurposing of the Speaking of deep property access, both the core proposal and the So... if the proposal was split up, I wonder how deep their shared concerns would be; but evidently there's already other proposals that are completely separate that would have to be considered too. Though, if the use of |
zenflow brought up that the spread syntax already exists and would accomplish the same thing without adding a new language feature. |
Spread syntax is ergonomic at one level deep, but after that, while perfectly functional, the syntax is not ideal and requires a fair bit of repetition. Considering: let myRec = #{
user: {
address: {
street: 'First St',
//...
}
//...
}
//...
}
let newRecord = #{
...myRec,
user: {
...myRec.user,
address: {
...myRec.user.address,
street: 'Second Ave'
}
}
} The update would be better as something like: myRec.user.address.street = 'Second Ave'; ... but that won't fly because we're dealing with immutable objects and the assignment operator can't "return" a value to assign to something else. Without a better way to update deeply nested properties in a record, I'd rather stick to immer and mutable objects for those use cases, and/or avoid nested records and tuples entirely. (Perhaps nested records would be considered bad practice by some anyway, but that's yet another debate) Edit: forgot where I was going with this - I guess the question I'm pondering is this: |
then rather than with, I’d prefer to see + used for that use case (and ideally - as well, if possible) |
As in let newRec = #{ x: { val: 2 }, y: 5 } + #{ x: { val: 0 } };
newRec === #{ x: { val: 0 }, y: 5 }; ... or .... let newRec = #{ x: { val: 2 } } + .x.val = 0 (Or something else?) (I'm assuming |
The former, and yes, ideally the operator would throw if you tried to combine an immutable type with a non-immutable one. |
Related: #19 |
@ljharb hmm interesting, I like it. It reinforces that there's certain special properties to these data structures too, and gets rid of the need for additional syntax for deep updates. Have you made a separate issue for the use of Main concern is whether overloading *(then again... are silent failures caused by strings + numbers really that enviable? Though that'd mean you'd have to stringify your records before string concatenation or interpolate them. That will trip up many devs, but would also encourage them to avoid blind string concatenation....) Using the user.street.address example: let newRec = myRec + #{ user: { street: { address: 'Foo Blvd' }}} ... a little more verbose but yeah that works well. Plus you also create the path if it doesn't already exist. |
Symbols already require explicit stringification, so there’s precedent there. |
@ljharb why do you think that combination of mutable and immutable data structures is a bad idea? It should not be a problem to convert a mutable object to immutable analog, and in cases when it would be required developers will do it - there is no second scenario to follow
About
and there is a demand on such shorthands - for example
but this alternatives uses string literals an thought are error prone
If we are talking about the operator that in some codebases would be used instead of |
Implicit coercion is something worth avoiding, even if it’s easy. Separately, one shouldn’t optimize for writing, but for reading - since the latter happens way more often than the former. |
For what it's worth, my own personal opinion is that it would be good to see a PR for removing
|
See #49, we intend to merge this sometimes this week |
|
Then what about a immer.js like API? Record.with(#{xyz: 1}, x => {
x.xyz = 2
}) // return #{xyz: 2} |
@Jack-Works I think Record.assign(#{ xyz: 1 }, #{ xyz: 2 }) === #{ xyz: 2 } |
Does it assign the record deeply? Does it also work for tuple? Record.assign(#{ xyz: #{abc: 1} }, #{ xyz: #{cde: 2} }) === #{ xyz: ??? } |
hmm, good question! As specified |
Deep assign might be a footgun imo It will be better to have a immer js like API . A Proxy like object is passed in, developer can modify it like an ordinary object, then after the modify, the proxy is revoked. |
Uh oh!
There was an error while loading. Please reload this page.
Continuing a thread from #1 – is there a compelling reason to include
with
in this proposal?I don't believe this proposal needs the
with
syntax to be viable. I also doubt that the proposedwith
syntax needs to be specific to immutable data structures –someObject with .b=5
would be handy as sugar forObject.assign({}, someObject, { b: 5 })
.Context:
The text was updated successfully, but these errors were encountered: