Ok, I have read more messages on this thread and looked at some of the supporting material that has been pointed at. The notes from the last meeting record a conversation before I arrived, and I'm not quite clear what it says was agreed on. In any case, I think the primary goals should be and seem to have been
* minimize magic * maximize security * codify something everyone can agree to implement The first two goals generally align well anyway. I think this is best served by something that seems at least close to what was agreed on: * The syntax that we've already agreed to on this thread: {__proto__: ....} is special syntax that initialized the [[Prototype]]. No need for anything even as mildly imperative as [[SetPrototype]]. * { [ "__proto__" ]: .... } is not special in any way, and creates a normal property named "__proto__". * Every object with a potentially mutable [[Prototype]] must be identified with a realm of origin. (Practically this will be "any object", which is good because that is what Weak References will need anyway.) * In the initial state of a normal realm, Object.prototype.__proto__ is an accessor property with the descriptor (making up names for the internal functions -- don't take the names seriously): { getter: [[ProtoGetter]], setter: [[ProtoSetter]], enumerable: false, configurable: true } * In this initial state, Object.getOwnPropertyDescriptor(Object.prototype, '__proto__') returns the above descriptor. No magic. * In this initial state, Object.getOwnPropertyNames(Object.prototype) returns a list which includes the string "__proto__". No magic. * Likewise for all other reflective operations, including "in". No magic. * The behavior of [[ProtoGetter]] is approximately function [[ProtoGetter]] () { return Object.getPrototypeOf(this); } except of course that it uses the internal function rather than the current binding of Object.getPrototypeOf. Just like Object.getPrototypeOf, this behavior is independent of Realm. It is also independent of whether [[ProtoGetter]] is invoked *as* an accessor or invoked otherwise, for example by using Function.prototype.call. * The behavior of [[ProtoSetter]] is approximately function [[ProtoSetter]] (newValue) { if ([[GetRealm]](this) !== [[GetRealm]]([[ProtoSetter]])) { throw new TypeError(....); // or should this be RangeError ? } this.[[SetPrototype]](newValue); } This behavior is independent of whether [[ProtoSetter]] is invoked *as* an accessor or invoked otherwise, for example by using Function.prototype.call. * Normal objects have a [[SetPrototype]] method like function [[SetPrototype]] (newValue) { // normal checks for proto acceptability // * either null or an object // * would not create an inheritance cycle this.[[Prototype]] = newValue; } ======== Warning: The rest of this is half baked ============ * Direct proxies have a [[SetPrototype]] method that invokes the handler's "setPrototype" trap. It is the *handler's* responsibility, not the proxy's, to set the target's [[Prototype]] to newValue. Once the handler returns to the proxy, the proxy checks if target.[[Prototype]] === newValue. If not, it throws. This enforces that a handler can only reflect the mutation of [[Prototype]] transparently if it already has setter which is the capability to do so.
_______________________________________________ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss