[Harmony Proxies] Non-extensible, sealed and frozen Proxies

Tom Van Cutsem tomvc.be at gmail.com
Wed Sep 7 23:48:55 PDT 2011

Thanks David for putting some of my fears to rest ;-)

Essentially you and Kevin concluded similarly that it's not necessary to
create some hybrid DOM emulation that would work with interchangeable native
and proxied DOM elements. So, let's close the "becoming a host object" can
of worms and instead focus on parameterizing [[Class]].

Simply parameterizing Object.prototype.toString should be easy. We've been
over this before. An extra String argument to Proxy.create, perhaps. If the
proxy becomes fixed, the newborn Object could inherit this String parameter
so that O.p.toString remains stable. That would hint at an
|Object.create(proto, pdmap, class)| primitive, where |class| is simply a
string such that O.p.toString on such an object just returns "[Object

Re. Array.isArray(aProxy) returning true: if truly necessary, it can still
be done by overriding Array.isArray such that it checks whether its argument
is an emulated array (e.g. via a WeakMap). Not ideal, but it works without
complicating either arrays or proxies.


2011/9/7 David Flanagan <dflanagan at mozilla.com>

> On 9/1/11 8:40 AM, Tom Van Cutsem wrote:
>> I promised to give an update on the work I've been doing to investigate to
>> what extent the Proxy API may support non-extensible objects.
>> In a nutshell: I now think it is possible for Proxies to emulate not just
>> non-extensible objects, but also sealed and frozen objects, given
>> appropriate invariant checks.
>>  Since this thread has started discussing NodeList and other DOM-related
> issues, and since I'm using Proxies to implement the DOM in pure JavaScript
> (see https://github.com/andreasgal/**dom.js<https://github.com/andreasgal/dom.js>)
>  I'll weigh in here with a few thoughts.
> First though, I'd like to say that Tom's original post in this thread was a
> thing of beauty.  Thanks, Tom, for the clearly articulated preface and
> history!
> David Bruant wrote:
>> 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?
> That seems like a can of worms that shouldn't be opened. I think the
> "become" option for fix() should only be used for objects that are
> sufficiently locked-down that they can be emulated with a plain-old object
> with appropriately set [[Prototype]] and [[Class]].  If I'm using a Proxy to
> emulate Array and its magical length property and preventExtensions() is
> called, I still need magical length behavior because properties can be
> removed.  I suggest that it is not worth allowing a proxy to "become" an
> Array in this case.  The proxy would just have to keep trapping so it can
> continue to provide the desired magical behavior.  But if my emulated array
> is frozen or sealed, then I can safely become a plain object with prototype
> Array.prototype and [[Class]] "Array".  It seems to me that if a proxy needs
> to "become" something other than a plain object, then it isn't really fixed,
> and it should keep trapping.
> As for [[Class]], I'm not sure if we really need to care about it, or if we
> only really care about the behavior of Object.prototype.toString().   For my
> work with dom.js I'm unable to comply with all WebIDL requirements because
> Proxies do not allow me to specify the [[Class]] for the proxy.  I only care
> about the return value of Object.prototype.toString(), however, so Allen's
> proposal (only barely articulated here: http://wiki.ecmascript.org/**
> doku.php?id=strawman:es5_**internal_nominal_typing<http://wiki.ecmascript.org/doku.php?id=strawman:es5_internal_nominal_typing>)
> to allow the return value of O.p.toString() to be set via object properties
> would solve my problem.
> In the Array case above, however, I suspect that an array-like Proxy that
> wanted to "become" an Array when frozen or sealed would like Array.isArray()
> to work for it, and so would like to be able to set [[Class]].  Allen is
> proposing to change the way that Array.isArray() works, however, so it
> wouldn't be tied to [[Class]] anymore. If he succeeds at that, then I think
> proxies (as currently defined) would never return true when passed to
> Array.isArray().  And if Array.isArray() can never return true for proxy
> objects, then presumably a proxy should not be able to fix() itself to
> "become" a true array object for which Array.isArray() does return true.
> If Allen is successful in abolishing [[Class]], then maybe you'll have to
> add Proxy.createArray() along with Proxy.create() and
> Proxy.createFunction()?
> If Allen is not successful, then it seems to me that we ought to be able to
> specify a [[Class]] value when calling Proxy.create() and that that value
> ought to be used when the proxy "becomes" a plain object via fix().
> This, I think, is what David Bruant proposed when he wrote:
>  Indeed, so if a [[Class]] is given to a proxy, it has to be done at proxy
>> creation so that the proxy and its fixed version are stable regarding
>> [[Class]] checks.
> Tom Van Cutsem wrote:
>  How about we adapt ideas from the "<|" proposal? Proxy.create already
>> takes a proto argument. The third argument could say whether the [[Class]]
>> of the proxy should be "Object" or should be the same as that proto. No
>> constructors.
>> That would probably also allow Object.prototype.toString.**call(proxy) to
>> return, e.g. [object Array], which is another outstanding issue.
>> I can see this working for Object and Array. Functions are covered by
>> function proxies. Do we need to consider other primitives?
>> I still don't see how it would work out for NodeList or other host
>> objects. Then again, I don't know whether there is a use case that requires
>> this.
> WebIDL requires NodeList objects to have a [[Class]] of "NodeList",
> Document object to have a [[Class]] of "Document", and so on.  Of course,
> since [[Class]] is only observable through Object.prototype.toString(),
> Allen's proposal to parameterize Object.prototype.toString() would address
> this, or proxies could address this directly.
> As for the more fundamental question: is there a use case for a proxy to
> "become" a host object?  I don't think there is much of a use case (at least
> not for DOM objects).  In my work with dom.js, the goal is to replace the
> native DOM entirely with a new implementation written in JS.  If it works,
> then my proxy-based NodeList implementation would be the only one there is:
> there wouldn't be any other kind of NodeList for it to become.
> Or, consider the case of a proxy that forwards to a native DOM Element
> object.  When frozen, it wouldn't make sense for it to "become" a new
> Element object because that new object wouldn't appear in the correct
> position in the document tree.
> Furthermore, the question of what the fix() method of a NodeList proxy
> should do is getting ahead of the DOM itself.  I don't think the behavior of
> DOM interfaces have been defined when preventExtensions, seal, or freeze()
> are called on them.  A fundamental feature of NodeList, for example, is that
> it is usually "live".   So if we're allowed to freeze a NodeList, we must
> either break the liveness contract and turn it into a static snapshot, or we
> must make the node from which the nodelist was derived non-modifiable.  This
> is unexpected action-at-a-distance, and the DOM doesn't even have a
> well-defined notion of readonly nodes, so neither option is really viable.
>  For now, at least, I suspect that trying to freeze a nodelist should just
> throw an exception.
> David Bruant asked:
>  Would it even be possible to have an "hybrid" DOM tree with native DOM
>> Node and emulated DOM Node?
> DOM Level 3 tried to define ways for document nodes to be shared between
> implementations, I think.  But that was really Java and XML stuff, and it
> has been dropped from the DOM Core spec.  I don't think that anyone has a
> goal to allow a proxy-based implementation of Element, for example, to be
> inserted into a native Document.  My understanding is that that is never
> going to work.  So the Proxy spec does not need to work to enable that.
>    David Flanagan
> ______________________________**_________________
> es-discuss mailing list
> es-discuss at mozilla.org
> https://mail.mozilla.org/**listinfo/es-discuss<https://mail.mozilla.org/listinfo/es-discuss>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.mozilla.org/pipermail/es-discuss/attachments/20110908/68b41ac3/attachment.html>

More information about the es-discuss mailing list