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

Recommend explicit extends null for shared structs #5

Open
rbuckton opened this issue Aug 28, 2021 · 2 comments
Open

Recommend explicit extends null for shared structs #5

rbuckton opened this issue Aug 28, 2021 · 2 comments

Comments

@rbuckton
Copy link
Collaborator

While it may be a little early for in depth syntax debates, if shared functions is something we may consider in the future then we might want to ensure that shared structs can eventually have something like a [[Prototype]] chain of other shared structs with shared methods/accessors (unless we essentially just flatten those as well). It would be nice to be able to have instanceof and constructor and to be able to share the shared struct constructor function.

As such, I would recommend that if we continue to use class-like syntax, that we might want to consider enforcing that shared structs have an explicit extends null to enforce the current [[Prototype]] semantics, otherwise we might not be able to change that in the future.

Example (based on current explainer):

shared struct class Foo extends null {
  ...
}
@syg
Copy link
Collaborator

syg commented Aug 30, 2021

Agreed that we eventually want to have something like a prototype chain that's shareable.

I definitely see the desirability of having a syntactic marker calling out the current [[Prototype]] semantics, but I have two questions:

  • Are you also proposing that [[Prototype]] be just null? The current semantics is that they throw when accessed. I'm happy to change those semantics, all I'm interested in is the best chance of future-proofing.
  • Do you think we'd need to make extends null work with constructors of plain classes too? Or do you think it's fine to say shared struct constructors just behave differently here?

@rbuckton
Copy link
Collaborator Author

Making accessing [[Prototype]] throw seems somewhat problematic given that the normal behavior for operators like in, ., and [] is to walk the prototype chain, which means you need to define unique behavior for [[GetPrototypeOf]], [[HasProperty]], [[Get]], etc.

If you define unique behavior such that "toString" in myStruct returns false, but we later add shared functions and a [[Prototype]] chain with a shared toString method, then suddenly that existing code might return true instead. By forcing an explicit extends null, we end up with a null [[Prototype]], similar to how class C extends null {} is supposed to work.

So, for

shared struct class C extends null {}
const c = new C();

the following would be true:

  • c's [[Extensible]] is false
  • c's [[Prototype]] points to C.prototype
  • C.prototype's [[Extensible]] is false
  • C.prototype's [[Prototype]] is null

This would allow us to eventually slot-in a default prototype at a later date. It might eventually allow c instanceof C to work as well, though I imagine we'd want the constructor C to be a shared function in that case.

We might be able to get away with this instead:

  • c's [[Extensible]] is false
  • c's [[Prototype]] is null

Although introducing a [[Prototype]] for the sake of methods in the future would also be observable via Object.getPrototypeOf.

Alternatively, these objects never have a [[Prototype]] and if/when we introduce shared methods we just flatten everything into the value. That would probably break super.method(), however.

Do you think we'd need to make extends null work with constructors of plain classes too? Or do you think it's fine to say shared struct constructors just behave differently here?

Possibly. Structs, as you've proposed, are essentially plain objects with some restrictions, so I would assume having a non-shared struct support extends null would be useful, if not required.


side note: Its very frustrating that the spec explicitly calls out class C extends null {} in https://tc39.es/ecma262/#sec-runtime-semantics-classdefinitionevaluation Step 8.f, but the null is somehow not handled during construction and V8 throws if you try to instantiate C.

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

2 participants