[Harmony Proxies] Non-extensible, sealed and frozen Proxies
david.bruant at labri.fr
Sat Sep 3 15:00:39 PDT 2011
Le 01/09/2011 17:40, Tom Van Cutsem a écrit :
> A first strawman (the "short-circuiting approach" on the wiki page)
> was based on having a proxy "cache" non-configurable properties, such
> that if the proxy hit the cache, it would no longer trap the handler.
> That design proved to be flawed, for several reasons, as pointed out
> by David Bruant, IIRC.
If i remember well, the main argument was that in the case of a
forwarding proxy, if non-configurable properties related trap call go in
the cache without actually calling the trap, then the forwarding proxy
cannot forward the operation to the target (and then fails at its
> The full implementation of such "non-extensible proxies" is here:
> The file's comments near the top contain a detailed description of the
> invariants enforced by this type of proxy.
Invariants on own properties trap (getOwnPropertyDescriptor,
defineProperty, delete, hasOwn) are a somewhat direct interpretation of
the invariants on the ES5.1 spec.
However, invariants imposed on potentially inherited properties may be a
bit more controversial. For instance, for the get trap, the fact that
the value is unchanged is enforced (L.641, !Object.is). This is a
"natural" extension of the ES5.1 invariant "If a property is described
as a data property and its [[Writable]] and [[Configurable]] are both
false, then the SameValue (according to 9.12) must be returned for the
[[Value]] attribute of the property on all calls to
[[GetOwnProperty]].", however, nothing in the spec enforces that the
[[Get]] (get trap) should use [[GetOwnProperty]] and then be affected by
the invariant. It is just how it happened to be spec'ed in 8.12.3 and
host objects could decide to do otherwise.
I'm not really sure what is the best to do. Either specify these
invariants in the spec or remove the checks from the implementation.
// - properties returned by the fix() trap are merged with fixed properties,
// ensuring no incompatible changes can be made when calling freeze, seal,
// will throw if any of the props returned already exist in
// fixedProps and are incompatible with existing attributes
I agree with this behavior. However it has some consequences. In order
to avoid throws, the proxy author has to remember which properties are
non-configurable (to avoid collisions when returning props) and the
values of these (to avoid throwing) which is a duplication of what the
engine has to remember to enforce the invariant. In order to avoid the
duplication, the engine could provide this information in some way
(additional trap argument? :-s).
Also, for traps to know whether a proxy has been fixed, the additional
proxy argument will be a good news (Object.isExtensible(proxy) from
within a trap).
I also like the idea of passing the type of operation (freeze,
preventExtensions, seal) as a string which can allow, for instance from
the fix trap of a forwarding proxy to do Object[operation](target).
> I (lightly) tested this implementation on FF6 (the implementation
> depends on both proxies and WeakMaps). For those interested:
> console-based test:
> browser-based test:
> Given the intricacy of the invariant checks, this code can use more
> eyeballs. There's also a number of unresolved TODO's that merit
> discussion, and some hints on a redesign of the fix() protocol. In
> particular, Mark and I have been discussing a protocol where a handler
> can _either_ tell the proxy that it wants to continue trapping, even
> after being fixed, or that it wants to "become" a regular object as
> before, with no more overhead for invariant checks. I think this gives
> handler writers the "best of both worlds" in terms of flexibility and
I really would like to see a native implementation of non-extensible
with non-configurable properties proxies, because i am still not sure
that there is an overhead in some cases. For instance, ES5.1 8.12.9
[[DefineOwnProperty]] for regular objects
(http://es5.github.com/#x8.12.1 ) has very similar checks than in your code.
Regardless, it's a good thing to provide the choice. Regarding the open
issue ("do we default to Object.create or do we want to allow for the
possibility of Array.create etc.?"), I think that the choice should be
given to create any sort of object (why not host objects such as
NodeList?). One question would be: how could this (easily) be achieved?
More information about the es-discuss