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

David Bruant bruant at enseirb-matmeca.fr
Tue Mar 1 10:25:18 PST 2011


Le 01/03/2011 15:35, Tom Van Cutsem a écrit :
> Hi,
>  
>
>     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.
Ok. I didn't know the intention to go away from the arguments object.

>  
>
>
>     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.
I was just saying that I didn't see any way that they can distinguish
and then implicitely asking if anyone else would see any. But the way
you explain it make clear that there is no reason code could distinguish.

On "should code be able to distinguish", I have no strong opinion. It
might be some way to enrich the proxy API. Anyway, since it's not
possible, the question can be forgotten for now.


> 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 :-)
Actually, under this option, you list "less consistent" as a con.
"Consistency" is used in two different points of view:
- The consistency listed as a con in the proxy handler API consistency
- The consistency you're talking in your paragraph is between the proxy
handler API and surface syntax.
I tend to agree that


About the last option "Proxy as argument only for particular traps", I
think that this option should be considered only if the method list
contains at least all methods which use prototypal inheritance. This
would grow the list to:
* getPropertyDescriptor
* getPropertyNames
* has
* get
* set
* enumerate
First, it makes sense, because in order to re-implement inheritance,
there is a need to access prototype, which can only be done through
Object.getPrototypeOf(proxy).
More practically, as an example, the default 'has' trap cannot pass
'proxy' as an argument to the 'getPropertyDescriptor' trap if it hasn't
itself a reference to the proxy. (actually, there is a similar issue
with get set and enumerate)
It should be noted that this option doesn't solve the first motivating
use case (shared handler) since some method are disadvantaged regarding,
for instance, being able to store per-proxy state.

Cheers,

David

>
> Cheers,
> Tom
>  
>
>
>     Cheers,
>
>     David
>
>
>
>>
>>     Cheers,
>>     Tom
>>
>>     2011/2/28 David Bruant <bruant at enseirb-matmeca.fr
>>     <mailto: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.currentProxyis
>>         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 <mailto: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/5a162fd5/attachment-0001.html>


More information about the es-discuss mailing list