15:59
<rbuckton>
I do wonder if it would make sense to have structs have a unique typeof. Since implementations have been somewhat opposed to new primitives (i.e., decimal) as they require considerable changes to the implementation, introducing a single new "user-defined primitive" type a la struct might be the answer. If we were to ever introduce operator overloading, we could hang it off of a user-defined "primitive" like a struct has some similarities to other primitives (i.e., per-realm/per-compartment prototype lookup). We could define new Decimal() to return an object, but later define Decimal() as returning a struct/shared struct instance so that it could work with shared memory (treating the object form as a boxed primitive). If we ever did introduce operator overloading to structs we could extend the struct version Decimal to support operators.
16:06
<Richard Gibson>
I will reiterate, it is probably important for compatibility that primitive (i.e., x === null || typeof x !== "object" && typeof x !== "function") ⇒ immutable. IOW, new typeof values are not acceptable for mutable values.
16:54
<ljharb>

it is a certainty, not a probability, that primitives must be immutable, but theres multiple ways to test for being primitive:

  1. has one of the primitive typeofs (this logic broke in ES2015 with symbols, and in ES2020 with bigints, so we can probably assume this isn't relied upon as much)
  2. doesn't have one of the object typeofs - ie, is truthy, and is typeof object or function. however lots of people forget function (like above), but indeed a new object typeof value would break anyone relying on this check.
  3. Object(x) === x means it's an object. this check should remain robust forever, but it's thought to be slower, so people tend to prefer the typeof lists.
17:01
<Mathieu Hofman>
I would extend 2 to say we probably should not let a falsy value ever be mutable, in case anyone starts their check with `!x` (with the aim of excluding `null`)
17:03
<Mathieu Hofman>
All that to say I agree that anything mutable should have typeof object, or we'd break a ton of code.
17:11
<Richard Gibson>
ack on typeof result "object" and "function" belonging in the same category; that was written in haste
17:12
<Richard Gibson>
* hmm, it is probably important for compatibility that primitive (i.e., typeof x !== "object" || x === null) ⇒ immutable, and even more important that strict (in)equality is time-invariant
17:38
<ljharb>
of course, if we could add a new predicate like isPrimitive or isObject, then i think we'd be able to push people to use it and be free to add more typeof values (under the same mutability/falsiness constraints ofc)
17:44
<rbuckton>
I'm not sure I 100% agree with this in principle. If there is ever a future that includes operator overloading, being able to implicitly coerce decimal 0.0 to a falsy value to match the rest of the language would be invaluable.
17:51
<ljharb>
that is a very big "if"
17:56
<rbuckton>
Sure, but maybe the best thing we could do for struct is to block most implicit coercion to give us a way forward if we ever wanted to take it, much like how "" + Symbol() throws today.
18:35
<Richard Gibson>
that's only disagreement with "should not let a falsy value ever be mutable" if you're expecting decimal instances to be mutable
18:39
<rbuckton>
I'm not, but expressing immutability in struct isn't straightforward. You essentially declare all of your data as # private fields and just never mutate them. It's not statically enforceable. I'd like to find a way to define a readonly or init-only mechanism for struct fields that works with one-shot initialization and avoids the hazards of prematurely sharing a struct instance during construction.
18:46
<Richard Gibson>
that seems moot unless you're proposing reflection of those restrictions in typeof output