proposal-mixins
proposal-mixins copied to clipboard
Evaluation time of computed property keys
As currently defined via desugaring to subclass factories, computed property keys are evaluated for each application:
mixin M {
[(console.log('a'), 'a')]() { /* ... */ }
}
class A extends Object with M {}
class B extends Object with M {}
desugars to:
let M(base) => class extends base {
[(console.log('a'), 'a')]() { /* ... */ }
}
class A extends M(Object) {}
class B extends M(Object) {}
This will evaluate the computed property expression twice, printing "a"
to the console twice.
It's possible to evaluate the computed property keys just once, at mixin declaration time:
const __M_computed_key_1 = (console.log('a'), 'a');
let M(base) => class extends base {
[__M_computed_key_1]() { /* ... */ }
}
This has some benefits and drawbacks, mostly around developer expectations:
- It's consistent with class computed property keys, which are only evaluated once when the class is declared.
- It's inconsistent with the explanation of mixins as subclass factories, whose bodies are evaluated for each application.
cc @littledan
This is a very clear summary of the trade-offs. I don't have much to add, just that potential future class features such as static field initializers, decorators and static blocks face similar issues of evaluation time.
Although similar to function mixins, I think it makes more sense one evaluation per definition now that they are more like class definitions.