A case for removing the seal/freeze/isSealed/isFrozen traps

Allen Wirfs-Brock allen at wirfs-brock.com
Sat Feb 16 14:31:45 PST 2013

On Feb 14, 2013, at 1:14 AM, Tom Van Cutsem wrote:

> 2013/2/14 Allen Wirfs-Brock <allen at wirfs-brock.com>
> On Feb 13, 2013, at 12:53 PM, David Bruant wrote:
>> Interesting.
>> So what would happen when calling Object.isFrozen on a proxy? Would Object.isFrozen/isSealed/isExtensible reach out directly to the target? or a unique "state" trap returning a string for all of them? ("state" is too generic of a name, but you get the idea)
> This is a question regarding proxy design, rather than the MOP. Either get/setIntegrity traps to the handler or it forwards directly to the target.  That's would be a design issue for Tom, but my starting point is to simply follow the current design decisions made for [[PreventExtensions]]/[[IsExtensible]]
> A get/setIntegrity trap with the invariant constraints of isExtensible/preventExtensions would be the obvious path to take.
> One thing that remains unclear to me: if the state of an object becomes explicit, we introduce the risk for this state to become inconsistent with the state from which it is derived.
> For example, setting the integrity of an object to "frozen" must still make all own properties non-configurable, i.e.
> Reflect.setIntegrity(obj, "frozen")
> should have the same effect as
> Object.freeze(obj)

yes, Object.freeze(obj) would be specified as performing:  obj.[[SetIntegrity]]("frozen")

> Likewise, turning the last configurable property of a non-extensible object into a non-configurable property should automagically change the state to "frozen", i.e.
> Object.defineProperty(obj, "lastProperty", { configurable: false }) // must update internal state as well as the property
> Reflect.getIntegrity(obj) === "frozen"

If I was starting fresh, I would say that Object.isFrozen(obj) is true only if Object.freeze(obj) (or equivalent Reflect.setIntegrity) has previous been performed and that Object.preventExtensions() followed by setting every property to non-configurable is not equivalent to performing Object.freeze. 

I wonder if we can make that change for ES6 without breaking anything.  Does anybody know of code that does Object.isFrozen(obj) checks without also having the expectation that obj would have been explicitly frozen using Object.freeze?

> Will this not just shift the current complexity someplace else?

Well, it means that for 100% backwards compatibility, Object.isFrozen would have to be something like:

1.  Let state = obj.[[GetIntegrity]]();
2   If state is "frozen" return true;
3   If state is "sealed" or "non-extensible", then return true if all properties are non-configurable and  non-writable
4  return false.

The real complexity saving is in simplifying the MOP/Proxy handler interface and also in making Proxy invariants  only sensitive to the explicit integrity state of an object.

>> Regardless on the final decision on (full) notification proxies, maybe these operations (isSealed/isFrozen) could have notification trap. The invariant is that the answer has to be the target one (all the time), so the trap return value is irrelevant. Like the getPrototypeOf trap.
> Right, one way or another these operations need to be part of the MOP.
> If we go for get/setIntegrity I wouldn't re-introduce all the derived operations as notification traps. Then we might as well leave things the way they are.

I meant either get/setIntegrity or isExtensible/preventExtensions/isFrozen/freeze/isSealed/seal need to be part of the MOP.  If we have get/setIntegrity we don't need the others (at the MOP/proxy trap level)


-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.mozilla.org/pipermail/es-discuss/attachments/20130216/b56f8ee7/attachment.html>

More information about the es-discuss mailing list