Do we really need the [[HasOwnProperty]] internal method and hasOwn trap

David Bruant bruant.d at gmail.com
Tue Nov 13 12:52:16 PST 2012


Le 13/11/2012 21:25, Tom Van Cutsem a écrit :
> 2012/11/13 Allen Wirfs-Brock <allen at wirfs-brock.com 
> <mailto:allen at wirfs-brock.com>>
>
>
>     I think there is agreement that [[HasOwnProperty]] is just an
>     optimization of ToBoolean([[GetOwnPropertuy]]).  Its only purpose
>     is to avoid unnecessary reification of property descriptors. If
>     that optimization isn't important we should just eliminate
>     [[HasOwnProperty]].
>
>
> I understand your point that on normal objects, implementations are 
> free to avoid actually allocating a property descriptor for has or 
> hasOwn checks. As far as the spec is concerned, the derived traps are 
> completely unnecessary: we could hypothetically rewrite the entire 
> spec to use only fundamental traps, and implementors would be free to 
> cut as many corners as they want for non-proxy objects.
>
> When I mentioned that derived traps avoid unnecessary allocations, I 
> was really thinking about this from the point-of-view of the ES6 
> metaprogrammer. Say I'm creating my own virtual object abstraction 
> whose properties reside in an external map, so I dutifully implement 
> all the traps:
>
> var store = new Map()
> var p = new Proxy( { } /* target doesn't matter */ , {
>   hasOwn: function(ignoreTarget, name) { return store.has(name); },
>   getOwnPropertyDescriptor: function(ignoreTarget, name) {
>     var e = store.get(name);
>     return e === undefined ? undefined : {value:e, ...};
>   },
>   ...
> };
>
> Say we remove the "hasOwn()" trap, calling the 
> getOwnPropertyDescriptor trap instead. Now my virtual object 
> abstraction does need to allocate a descriptor.
For the particular case you've written, when going for 
hasOwnProperty.call or the in operator, the JS engine knows it needs to 
output a boolean, so it can "rewrite" (or contextually compile) your 
trap last line as "e===undefined" (since "undefined" is falsy and 
objects created by object literals are truthy). In that particular case, 
the allocation isn't necessary provided some simple static analysis.
Maybe type inference can be of some help to prevent this allocation in 
more dynamic/complicated cases too. I would really love to have 
implementors POV here.


> Your proposal of adding a flag to the trap fixes that, but IMHO in a 
> way that confuses the intent of the operation being intercepted:
>
> var store = new Map()
> var p = new Proxy( { } /* target doesn't matter */ , {
>   getOwnPropertyDescriptor: function(ignoreTarget, name, needDescriptor) {
>     if (!needDescriptor) { return store.has(name); }
>     var e = store.get(name);
>     return e === undefined ? undefined : {value:e, ...};
>   },
>   ...
> };
>
> It's dawning on me that the main reason I dislike adding flags to the 
> fundamental traps is that it breaks the 1-to-1 symmetry with the 
> operations that they intercept:
>
> Object.getOwnPropertyDescriptor(proxy, name) // traps as 
> getOwnPropertyDescriptor(target, name)
>
> This symmetry should make it relatively easy for an ES5 programmer to 
> pick up the handler API. The signatures look familiar (at least for 
> all operations that are expressed as function calls). Adding extra 
> flags breaks the symmetry.
I agree. As I suggested in my other answer, the flag isn't necessary. 
Very much like it's not for the internal operation.

David
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.mozilla.org/pipermail/es-discuss/attachments/20121113/8a1f861b/attachment-0001.html>


More information about the es-discuss mailing list