[[SetInheritance]] (was: General comments response (was Re: ES6 Rev13 Review: MOP-refactoring, symbols, proxies, Reflect module))

# Tom Van Cutsem (13 years ago)

2012/12/30 Allen Wirfs-Brock <allen at wirfs-brock.com>

On Dec 29, 2012, at 2:37 PM, Tom Van Cutsem wrote:

  • [[SetInheritance]]/Reflect.setPrototypeOf: I'm not sure this was agreed upon. Especially since proto is currently specified as a data property. This means there is no setter that separately reifies the ability to set the prototype. Thus, it's perfectly possible to just exclude [[SetInheritance]] and Reflect.setPrototypeOf from the spec.

No, [[SetInheritence]] needs to be part of the MOP. Certainly to define the semantics of proto takes more than just saying it is a data property. Regardless of whether it is ultimately reflected as that or as an accessor property the semantics of setting it has to be specified in some manner that likes it to the value that is retrieved by [[GetInheritance]]. Also, there are already in the spec. at least three forms of objects (ordinary, exotic symbols, exotic proxies) with different implementations of [[SetInheritance]] so an internal MOP method has already proven to be a useful specification device.

Ok. I did a search for [[SetInheritance]] in the Rev13 draft and the only place this method was called was from Reflect.setPrototypeOf and the Proxy "setPrototypeOf" trap default. That's why I thought it could easily be removed. I now see the note that appendix B3.1 (specifying proto) is not yet up-to-date. Probably when it's updated, this part of the spec will also call [[SetInheritance]].

Whether or not it is reflected as a Proxy trap is a separate matter. When this was discussed recently on es-discuss, the point was made that even if [[SetInhertance]] intersession by a trap is disallowed (ie, a trap can't prevent [[SetInheritance]] with the same value from being automatically invoked on the target) it is still important to get a notification that [[SetInheritiance]] has occurred. This is similar, to other traps whose handler behaviors are restricted but were still deemed useful from a notification perspective. I believe that the conclusion of that discussion we seemed to have agreement that [[GetInhertiance]] should be handled in this same manner.

It seems there are two routes we can take a) Introduce a "setPrototypeOf" trap (as currently specified), with the invariant check that the new prototype must match that of the target if setPrototypeOf returns true (a return value of "false" would mean the proxy rejected the prototype change).

b) Not treat proto as a magical property on proxies, and get rid of the "setPrototypeOf" trap. This implies that aProxy.proto = val just triggers the "set" trap. This delegates the choice of whether to treat proto as magical or not to every individual proxy handler.

Reflect.setPrototypeOf is not essential and simply there to provide a point

of further discussion. I think it is desirable that the Reflect.* interface be an accurate reflection of the internal MOP.

I agree that if we take choice (a) (i.e. introduce a "setPrototypeOf" trap) then we should also have the corresponding Reflect.setPrototypeOf primitive.

Any and all, restrictions that are applied to prototype can also be applied to Reflect.setPrototypeOf. In fact, the specification of it can be essentially:

function setPrototypeOf(target, parent) { target.proto = parent };

Yep.

I'm also of the school that if we are going to accept a mutable inheritance chain as a standard part of the language then we might as well embrace it rather than treating is as the black sheep that we try to pretend isn't really there.

Agreed. Although we should make an effort to make it easy for sandboxes/dialects to remove the feature from the language.

That said, I think this issue is orthogonal to our choice of whether or not to expose "setPrototypeOf" as part of the MOP. Even if we do expose it, any sandbox that wants to take away the ability the set the prototype can simply poison Reflect.setPrototypeOf in addition to deleting Object.prototype.proto.

# Brandon Benvie (13 years ago)

On Monday, December 31, 2012, Tom Van Cutsem wrote:

That said, I think this issue is orthogonal to our choice of whether or not to expose "setPrototypeOf" as part of the MOP. Even if we do expose it, any sandbox that wants to take away the ability the set the prototype can simply poison Reflect.setPrototypeOf in addition to deleting Object.prototype.proto.

Ive realized this is actually a potentially serious flaw with the module system with to how the builtin modules expose features. If you introduce Reflect.setPrototypeOf (or more generally, anything exposed as an export of a system module) there is no way for something like SES (user level) to remove access to it. There's no way to monkey patch these things or remove them or add new features to them because the modules aren't externally mutable. delete Reflect.setPrototypeOf is not currently an option.

# Allen Wirfs-Brock (13 years ago)

On Dec 31, 2012, at 7:28 AM, Brandon Benvie wrote:

On Monday, December 31, 2012, Tom Van Cutsem wrote: That said, I think this issue is orthogonal to our choice of whether or not to expose "setPrototypeOf" as part of the MOP. Even if we do expose it, any sandbox that wants to take away the ability the set the prototype can simply poison Reflect.setPrototypeOf in addition to deleting Object.prototype.proto.

Ive realized this is actually a potentially serious flaw with the module system with to how the builtin modules expose features. If you introduce Reflect.setPrototypeOf (or more generally, anything exposed as an export of a system module) there is no way for something like SES (user level) to remove access to it. There's no way to monkey patch these things or remove them or add new features to them because the modules aren't externally mutable. delete Reflect.setPrototypeOf is not currently an option.

I'll leave it to Dave or Sam to elaborate, but I don't think this is correct. My understanding, is that such censoring can be accomplished by configuring a module loader to return an alternative implementation of the "@Reflect" (or however it is identified) which could either not export Reflect.setPrototypeOf or export an alternative implementation.