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

Reply via email to