Hacker News new | ask | show | jobs
by LegionMammal978 613 days ago
Thanks for the history! Reading through the issues, I agree with you that some of the motivations against objects in records seem pretty strange. Mostly they seem to be around existing JS-written 'membranes' (related to the SES stuff mentioned above?) getting confused by primitives-containing-objects, depending on which permutation of typeof checks they use. Out of curiosity, do you think that the Shadow Realms proposal they refer to will ever go anywhere?

Otherwise, there's the argument that "x.y" syntax shan't be used to access a mutable object from an immutable record, but that just feels like the all-too-common motive of "we must ensure that users write morally-correct code (given our weird idiosyncratic idea of moral correctness), or otherwise make them pay the price for their sins".

1 comments

> Out of curiosity, do you think that the Shadow Realms proposal they refer to will ever go anywhere?

I haven't really been following the Shadow Realm proposal (I'm not part of TC39, so only familiar with certain proposals), but I don't think it should conflict with R/T.

If R/T values are allowed to be passed between realms, they should effectively be "transformed" such that eg, `f(#[v])` is equivalent to `f(#[f(v)])` (where `f` is the transformation that allows values to be passed between realms). For "deeply immutable" values (no object references), `f(v)` will simply return `v` (eg, `#[42]`, f(#[42])` and `f(#[f(42)])` are all the same) and a membrane should be able to trivially optimise this case.

From this comment[0] it sounds like `f({})` in the current Shadow Realm proposal will throw an error, so I'd expect that `f(#[{}])` would also throw an error.

As you were pointing out, I think the only real contention between R/T and realms is in existing JS implementations of membranes, particularly because they might use the following condition to detect if something is "deeply immutable":

  v === null || typeof v !== "object" && typeof v !== "function"
If `typeof #[{}] === "tuple"`, then their `f` function will pass that value through without handling the contained object value by throwing or by creating/finding a proxy.

If `typeof #[{}] === "object"`, it should be fine because `f(#[{}])` will either throw or create/find a proxy for the tuple. There might be some unexpected behaviour around equality of R/T values passed through the membrane, but this is pretty obscure and it should be fixed once the membrane library is updated to handle R/T values.

Personally, I'm still not 100% convinced that the assumptions made from the above condition are important enough to cause such a change to the proposal, but I don't see the value of `typeof #[]` as being a usability issue. Code that needs to check the types of things is a bit smelly to me, but in cases where you do need to check the type, `typeof v === "tuple"` and `Tuple.isTuple(v)` both seem usable to me, so just making `typeof #[] === "object"` should be fine and it solves this hypothetical issue. This is similar to array objects, which are also fundamentally special (`Object.create(Array.prototype)` is not an array object) and are detected using `Array.isArray(v)`.

> Otherwise, there's the argument that "x.y" syntax shan't be used to access a mutable object from an immutable record, but that just feels like the all-too-common motive of "we must ensure that users write morally-correct code (given our weird idiosyncratic idea of moral correctness), or otherwise make them pay the price for their sins".

Agreed, and I've pointed out[1] that even the current proposal doesn't address this, since unless you've done some defensive check on `x`, there's nothing stopping someone passing a mutable object for `x` instead of a record. If you do want to perform a dynamic[2] defensive check, perhaps you should be asking "is it deeply immutable?" or even checking its shape rather than "is it a record?".

[0] https://github.com/tc39/proposal-record-tuple/issues/390#iss...

[1] https://github.com/tc39/proposal-record-tuple/issues/292#iss...

[2] If you're using a type system like TypeScript, this check should happen statically, because you'll use a type that specifies that it's both a record and the types of the properties within it, so your type will encode whether or not it contains mutable objects

Thank you so much for the insight!