Open brianmhunt opened 5 years ago
@sepehr what you're describing isn't that difficult to implement in ES, but don't expect that the language supports it with syntax. The trick is to control the order of instances and prototypes while using accessors to keep data on the appropriate object. As an example, for an instance who's class was defined as roughly C extends B extends A, the instance structure would look like this:
let instance = { //C instance
//C instance property accessors
__proto__: { //B Instance
//B instance property accessors
__proto__: { //A instance
//A instance property accessors
__proto__: { //C prototype
__proto__: { //B prototype
__proto__: { //A prototype
__proto__: Object.prototype
}
}
}
}
}
};
If classes were structured like this, you could get what you wanted, but as you might guess, there are several problems with this design, not the least of which is the need to defeat copy-on-write semantics for properties behind a prototype interface by using accessors. That means the actual, per-class instance property storage is somewhere else. Not very memory efficient, or fast.
Another problem is that for classes extending native classes, the instance of the native object needs to be the top object. That alone interferes with inheritance, as any own property of the native object will always override all properties of subclasses.
It is a common pattern to have a parent class that sets the properties of children, but the current TC39 spec introduces a problem with this pattern: children properties are set to
undefined
.Just one illustrative example (in Typescript, since the types aid the illustration):
The current spec 2.7 DefineField(receiver, fieldRecord) at
2.7.6
mandates that propertiesa
andb
be assigned at the construction ofChild
the valueundefined
.Based on my own experience, this behaviour obscures bugs that can be subtle and difficult to debug. If introduced into e.g. Typescript this would have the potential to break a lot of code.
This problem would be avoided if a class does not assign
undefined
if the parent has already assigned a value (i.e. the property exists). I feel quite strongly that this is the behaviour most developers expect.If one wishes to obscure properties from parents, it could be explicitly done with a new keyword such as
protected
orown
i.e.I noted that this is the behaviour honoured by
@babel/plugin-proposal-class-properties
, and that it's already been identified there as an issue https://github.com/babel/babel/issues/8280 (closed on the basis that it's in compliance with this spec).