-
Notifications
You must be signed in to change notification settings - Fork 25
'this' in static initializers #50
Comments
This might be problematic, for one of the big use cases is |
@ljharb, that involves instantiating the class before it is finished being defined, and looks to me like an excellent reason to prohibit access to What would it even mean? If I have class C {
static singleton = new this;
static foo = sideEffect(0);
[(sideEffect(1), 'a')] = sideEffect(2);
constructor(){ ... }
} is Also, I'm not sure what the use case is for it. This isn't Java; I'd think you could just use an object literal. Or |
No, this is specifically enabled in steps 29-32 here: https://tc39.github.io/proposal-class-public-fields/#runtime-semantics-class-definition-evaluation The class is guaranteed to have finished construction and binding before static field initializers execute (which happens in static-field order). |
(Note that the class's variable binding is initialized in 23.a) |
Assume
It is instantiated with the one defined by the user
At least one compelling use case (as with instance fields) is to reference other statics on the class without having to state the name of the class (refactoring, etc). class UnitCircle {
static pi = 3.14;
static circumference = 2 * this.pi;
} |
Going to close this out, but as always: Please re-open in the case that I've missed anything |
One thing that I didn't see discussed here: if you let class C {
static has = 'has' in this;
} Then, I'm also wondering how the current semantics mesh with the @bterlson and @wycats 's proposal for unified class evaluation; I'd be interested in their thoughts (or has this already been discussed somewhere?). |
FWIW, TS does not allow The proposal here gels exactly with the BT/YK evaluation order - static initializers run after the lexical binding of the class is removed from TDZ (as in, it's effectively the same as if the static members were added after the class declaration). |
@bterlson Good to hear that it fits with your model. My only objection was that adding initializers afterwards would make the intermediate state of the class observable, showing that the static properties are added one by one. But, considering that this is already the case with instance properties, it's not so bad. As for |
@littledan I think |
No, I can't think of a good reason to disallow it, and it makes sense since |
I am not a fan of this |
@caitp Why should the value of |
@littledan syntactically, it’s not a method/function, and even implementation-wise there isn’t a strong argument for it to be. It’s more in line with object literal elements: (function() {
let a = ({
a: this.a
}).a; // “a”
let b = (class {
static b = this.b;
}).b; // “b”
}).call({ a: “a”, b: “b” }); Since there is no clear function boundary, it is bizarre for |
I wonder if something related to https://github.com/tc39/proposal-class-access-expressions would help. Unless it's really really hard to implement (it does seem harder than I imagined), I would rather stick with the current scoping semantics, given the lengthy debate that led us here, multiple implementations, and large test suite that we've already developed. |
It looks straight forward to me, I would 100% prefer that to messing with There is one thing that could make it slightly more difficult (only slightly), which is whether Given that there are workarounds which don't require the proposal, the proposal which would only improve things (and be more in line with modern languages), and the fact that altering |
Well, class access expressions is more proposed as an additional thing on top, rather than a replacement for I still think it's a bit late to change semantics here; it's best to change them during Stage 2 or earlier. |
I disagree, I think we should revisit it. There are few VM implementations, and the current semantics are not good for anybody. The “extra fluff on top” proposal isn’t needed for the initial implementation, since named classes can already reference themselves easily. It’s just a bonus convenience to allow it in anonymous class contexts. You don’t mess with
should refer to the same Addendum: With the current design, including instance fields, you have 3 different meanings of You could make the argument that For static fields, the initializer can be assumed to be evaluated inline in the current execution context, intuitively that's how it would be evaluated, so altering |
If we stick with the model last settled on of initializer bodies being scoped as methods, and do the same for static fields, then classes would be accessible while they were being constructed via
this
. We have a TDZ for class names specifically to avoid this (it previously only arose for computed method names); I believethis
should likewise have a TDZ, being bound at the same time as the class name.Thus the following code would be an error:
and this would be legal:
Thanks to @ajklein for pointing this out.
(NB: The spec text as it currently stands has no special scoping applied to static initializers, so
this
refers to whatever it would outside of the class, but I believe that doesn't reflect the last consensus of the committee.)The text was updated successfully, but these errors were encountered: