-
Notifications
You must be signed in to change notification settings - Fork 27
Static class field inheritance issues #5
Comments
Normal static properties of parent classes are already part of the language; there's just not a nice syntax to declare them. class A {}
Object.defineProperty(A, 'field', {
configurable: true,
writable: true,
value: 'static field'
})
class B extends A {}
B.field // 'static field'
A.field = 'changed'
B.field // 'changed'
B.hasOwnProperty('field') // false
Object.getPrototypeOf(B).hasOwnProperty('field') // true |
I refer to those as "normal non-static properties of parent classes" right at the top of this issue, and distinguish them from static fields (i.e., those declared as |
JavaScript already has its prototype chain inheritance model. Even if we can conceive of another object model that might have certain nice properties, I think it'd add a lot of complexity to support both. Let's settle on static public fields as they are currently proposed--own properties of the constructor where they are defined, and nothing more complicated. |
I thought about posting this as a comment on #2, but upon completion it read more like a restatement of both that issue and #1.
Question 1: Should static fields from the parent be initialized on subclasses?
Normal non-static properties of parent classes are already part of the language and are not copied, so this behavior would set static field declarations apart from both non-static properties and from static methods.
Even so, I think the answer should be "yes" (for reasons elaborated upon below).
But it prompts a followup.
Question 1a1: Should static fields on subclasses be initialized with the current value from the parent, or the initial value?
I think the best answer is "current value", despite the resulting dependence upon when a subclass is defined:
On the other hand, not initializing static fields from the parent has (in my opinion) even more surprising behavior...
Question 1b1: Should assignment to a static field in an inherited method from the parent's lexical scope create a new binding on the subclass?
If yes:
If no:
Static private fields
Regarding static private fields, their very existence must be kept secret from subclasses.
But I think that requirement can inform deliberation on the above options.
Question 2: Should static private fields be accessible from inherited methods called on subclasses?
If the answer is "no", then static private fields essentially break class inheritance (because even a simple method like
static getPrivateField() { return this.#privateField; }
would throw an exception when the receiver is a descendant class). So let's provisionally make it "yes".Question 2a1: Should static private field access be locked to the original lexical scope?
A "no" here would violate the secrecy requirement (e.g.,
(class Sub extends Base { static #privateField = "spied on Base" }).getPrivateField()
), so let's again say "yes":This behavior is analogous to every class having a WeakMap in which every key is a class (equal to or descended from the context class) and the corresponding value holds the current value for each static private field in the lexical scope of the context class. This perspective also informs what should happen during evaluation when an attempt is made to access a private field from a value that is not a class equal to or descended from the context class (e.g.,
(class Base { static #x = "trusted"; static x(){ return this.#x } }).x.call(class Decoy { static #x = "untrusted" })
)—a runtime error.Conclusion
The above makes sense to me, but please poke holes in it if you can. Also note that the proposed resolution to Questions 2 and 2a1 is independent of Question 1a1, and a case could be made for resolving the latter by holding onto initial values (although, as noted, that is not my preference and doesn't feel like a good fit for ECMAScript).
The text was updated successfully, but these errors were encountered: