[Harmony proxies] Another idea to give handler access to proxies

Tom Van Cutsem tomvc.be at gmail.com
Tue Mar 1 06:35:47 PST 2011


> Here is another idea:
> Adding a 'currentProxy' property to the arguments object of a handler
> methods when it's called as a trap (otherwise, the method is just a regular
> function). It's very close to the idea of adding an argument without the
> inconvenient/embarassement of placing it. It's generic, so it solves the
> issue for future traps. It obviously comes to the price of some sort of
> inconsistency, because adding things to the arguments object hasn't been
> done before (not that i'd be aware of, at least).

With the introduction of the spread operator in Harmony, the intention is to
move away from using |arguments|. I wouldn't want to tie the proxies
proposal this tight to the |arguments| object. Also, as you note, there is
no precedent for it. I would also claim that it still doesn't feel like a
natural place to store the proxy.

> Within a handler method, there would be a subtle difference. Let's take the
> example of a derived trap implementation (has trap):
> --------------------------
> var h = {
> getPropertyDescriptor: function(name){return arguments.currentProxy;},
> has: function(name) { return !!this.getPropertyDescriptor(name); }
> }
> var p = Proxy.create(h);
> 'a' in p; // false
> --------------------------
> When 'has' is trapped, it calls the handler method like a regular method,
> so there is no special treatment to arguments (arguments.currentProxy ===
> undefined => !!this.getPropertyDescriptor(name) === false)
> If 'has' was implemented as:
> has: function(name) { return
> !!Object.getPropertyDescriptor(arguments.currentProxy, name); }
> then the 'getPropertyDescriptor' handler would be called as a trap, so
> 'currentProxy' would be 'magically' added to the arguments object.
> I'm realizing that my idea raises a question that had no reason to exist
> before.
> Before, proxy weren't accessible from handler methods, so in order to
> implement derived traps, one handler method could only have access to other
> handler methods through 'this'. However, if 'proxy' becomes accessible
> within handler methods (no matter how), it could be considered to
> reimplement derived traps with actual fundamental trap trapping. I would
> personnally feel this to be more consistent with the idea of a mapping
> between traps and internal methods.
> However, as of today, besides my arguments-proxy-patching idea, I do not
> see how to notice a difference between 'this.getPropertyDescriptor(/*proxy,
> */ name)' (proxy argument depending on how we give proxy access to handler
> methods) and being trapped on 'Object.getPropertyDescriptor(proxy, name)'.

There should not be a difference. Any code that has access to both a proxy
and to its handler object can choose to either invoke the traps explicitly
on the handler, or implicitly via the proxy object. I don't see why a trap
should be able to distinguish both cases.

Of the proposals listed on the strawman wiki page, I prefer the "Proxy as
additional argument" option. I think consistency between the traps and the
Javascript code that they intercept is what matters most in practice, and
what will minimize bugs for developers that are not familiar with spec.
details. IOW, calls like "Object.defineProperty(proxy, name, pd)" would then
be trapped by "function defineProperty(proxy, name, pd) {...}". Principle of
least surprise and all that :-)


> Cheers,
> David
>  Cheers,
> Tom
> 2011/2/28 David Bruant <bruant at enseirb-matmeca.fr>
>>  Hi,
>> After reading this page (
>> http://wiki.ecmascript.org/doku.php?id=strawman:handler_access_to_proxy),
>> I thought of another idea.
>> Maybe that instead of adding an argument to all handler methods, we could
>> add a property to the handler.
>> Each time a proxy p method m is trapped (with handler h):
>> - Object.defineProperty(h, 'currentProxy',  {value: p, configurable:true}
>> )
>> - call the m trap (which can freely use this.currentProxy)
>> - delete h.currentProxy (that's why the property has to be configurable)
>> An implementation could run some static analysis to see if the handler is
>> an actual object and if this.currentProxy is actually used in the trap to
>> avoid the overhead of define+delete. They would have to be performed if the
>> handler is itself a proxy.
>> In order to reserve the 'currentProxy' (no strong conviction on the name.
>> It could also be 'proxy') name, Proxy.create and Proxy.createFunction could
>> throw an error is such a property is already defined.
>> On issue is that within a handler method, I could do:
>> {keys: function(){
>>     Object.defineProperty(this, 'currentProxy', {value: 'gotcha',
>> configurable:false});
>>     }
>> }
>> This is notoriously stupid, but it would make the "inner delete" throw an
>> error. The issue I'm raising is that 'configurable' controls both the fact
>> that a property can be redefined through Object.defineProperty and deleted.
>> Anyway, this solution sweeps away any argument positionning issue. It is
>> very generic and for sure, any trap current or future will need access to
>> the proxy, so it solves the problem for potential future traps.
>> On the other hand, there may be some property configuration issues and
>> maybe some performance issue since the two additional calls may be needed at
>> each trap call (even though static analysis could help out with this).
>> This idea is unperfect like the others, but it might be worth
>> investigating in that direction.
>> David
>> _______________________________________________
>> es-discuss mailing list
>> es-discuss at mozilla.org
>> https://mail.mozilla.org/listinfo/es-discuss
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.mozilla.org/pipermail/es-discuss/attachments/20110301/4b22b18a/attachment.html>

More information about the es-discuss mailing list