You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
This repository was archived by the owner on Jan 25, 2022. It is now read-only.
The reason for the error is that the receiver is Sub, which does not have a #field defined on it. One possible approach is to allow for a prototype walk just as we do for any other property lookup. We could support this by splitting private members into several parts:
Space reservation for a private name on an object, indicating whether it is addressable when the object is the receiver.
Definition of a private member on an object.
Then we would apply the following semantics, given private name P:
non-static private methods/accessors:
During class declaration evaluation:
Add a reservation on the class prototype for P with the value "reserved".
Add a private property definition to the class prototype for P.
During construction:
Add a reservation on the instance for P with the value "addressable".
non-static private fields:
During construction:
Add a reservation on the instance for P with the value "addressable".
Add a private property definition to the instance for P.
static private methods/accessors and fields:
During class declaration evaluation:
Add a reservation on the class constructor for P with the value "addressable".
Add a private property definition to the class constructor for P.
If the class is a subclass, Add a reservation on the class constructor for each "addressable" private name on the superclass constructor.
Then, when performing a get or set of a private property P on object O, with receiver Receiver:
If O does not have a reservation for P, throw a TypeError exception.
Let ownDesc be the private property definition for P on O.
If ownDesc is undefined, perform this operation on O.[[GetPrototypeOf]]() instead as O and passing P and Receiver as is.
If Receiver does not have a reservation for P, or the reservation for P on Receiver is not "addressable" throw a TypeError exception.
Perform the remaining get or set steps.
This would result in the following behavior:
non-static private methods/accessors would be defined on the prototype, but cannot be accessed directly (e.g. C.prototype.#method() is an error). This keeps the observable semantics the same as the current spec.
non-static fields are defined on the instance, as per the current spec.
static private methods, accessors, and fields are defined on the constructor.
static methods on a subclass can use this and have the same semantics for private fields that they do for public fields.
Calling Sub.get() above would succeed, returning the value of Base.#field.
Calling Sub.set(2) above would succeed, setting the value of Sub.#field to 2, but leaving Base.#field as 1.
The text was updated successfully, but these errors were encountered:
Alternatively, we don't add the reservation and if we bottom-out on a private get or set where no object in the prototype chain defined the private member, we throw a TypeError exception.
This does seem to be well-defined spec text which addresses @jridgewell's issue. However, it doesn't meet another design goal of private in classes: That no observable or hookable meta-object operation is done in the course of private field access. You can put a Proxy in the prototype chain and get a hint of what's going on here, or even change the thing being bound to dynamically. That's something the private class element proposals try to avoid.
We've thought about a bunch of alternatives for how private methods could work through inheritance. I've summarized this idea and others, about some sort of prototype chain, in this document. Ultimately, it seems like the downsides outweigh the upsides.
In the September TC39 meeting we discussed issues with private static fields, e.g.:
The reason for the error is that the receiver is
Sub
, which does not have a#field
defined on it. One possible approach is to allow for a prototype walk just as we do for any other property lookup. We could support this by splitting private members into several parts:Then we would apply the following semantics, given private name P:
"reserved"
."addressable"
."addressable"
."addressable"
."addressable"
private name on the superclass constructor.Then, when performing a get or set of a private property P on object O, with receiver Receiver:
"addressable"
throw a TypeError exception.This would result in the following behavior:
C.prototype.#method()
is an error). This keeps the observable semantics the same as the current spec.this
and have the same semantics for private fields that they do for public fields.Sub.get()
above would succeed, returning the value ofBase.#field
.Sub.set(2)
above would succeed, setting the value ofSub.#field
to2
, but leavingBase.#field
as1
.The text was updated successfully, but these errors were encountered: