[[Invoke]] and implicit method calls

Allen Wirfs-Brock allen at wirfs-brock.com
Mon Sep 23 10:45:13 PDT 2013


On Sep 23, 2013, at 1:33 AM, Tom Van Cutsem wrote:

> 2013/9/21 Allen Wirfs-Brock <allen at wirfs-brock.com>
...
> 
>> c) double-lifting needs 2 traps (get + invoke) rather than just get.
> 
> I don't think so, using [[invokeFunction]] instead of [[Invoke]] eliminates the need for two:
> 
> the current dispatch mechanism for Proxy Mop operations is essentially
>     let trap = handler.[[Get]]("handlerName");
>     ...
>     trap.[[Call]](handler,args);
> 
> if [[InvokeFunction]] was available this would become
> 
>     let trap = handler.[[Get]]("handlerName");
>     ...
>     handler.[[InvokeFunction]](trap, handler,args);
> 
> The default behavior of [[InvokeFunction]] on a Proxy that does not have a corresponding "invokeFunction" trap defined is equivalent to a [[Call]] of the passed function so the behavior would be exactly the same.  All the metameta handler needs to define is "get".
> 
> Ok, I stand corrected. But that default behavior surprised me. The default behavior of all other traps is to forward the intercepted operation to the target. The way you describe things, this would not be true of "invokeFunction".

Except the above isn't showing the control flow for the default path through a Proxy mop operation it is showing the path when a trap is defined.  As it has done is replaced the [[Call]] to the trap (which passes the handler as the this value) with an [[InvokeFunction]] on the handler.    Since the Proxy object that is the handler (for example, https://gist.github.com/tvcutsem/6536442 ) does not define a "invokeFunctiuon" trap it takes its default which is to forward [[InvokeFunction]] to its target (dummy in the example).. That is an ordinary object so it will get default [[InvokeFunction]] behavior which is just to do a [[Call]] using the explicitly passed this value and arguments.

(BTW, this is somewhat tricky to work out, but I believe it all hangs together.  But we should keep looking at this double-lifting scenario to make sure I haven't missed something).


>  
>> 
>> At that point, we're better off dropping [[InvokeFunction]] entirely.
>> 
>> As Brendan mentioned, methods are extractable in JS. A new MOP operation doesn't relieve proxies from honoring that contract.
> 
> It still appears to me that [[Get]]+[[InvokeFunction]] and respec'ing F.p.call/apply in terms of [[InvokeFunction]] is the closest semantic match to this expected behavior plus has the least anomalies WRT transparent proxying of built-ins with private state (and user defined classes that we WeakMaps for private state).
> 
> Except that respec'ing F.p.call/apply changes the [[Call]] behavior of existing non-proxy functions. Am I the only one to think this is potentially a serious hazard?

Only if the this argument is a proxy and presumably no existing use of call/apply was written with the expectation that the this value it was passing might be a proxy.  It think it is much more likely that they expect the obj.m() :: obj.m.call(m) equivalent than anything else.
...
> 
> Indeed, there are trade-offs and there is no silver bullet.
> 
> The status-quo, which I advocated, entails:
> 
> - we keep the invoke() trap, with its current signature: invoke(target, propertyName, argsArray, receiver)
> - conditional method calls in the spec are still expressed as [[Get]] + [[Call]], following the common JS idiom
> 
> After your comments, I would add:
> - we change ForwardingHandler.get to automatically re-bind |this| by wrapping function-valued data properties of its target
> 
> The only drawback of the status-quo, that I see, is that proxies that do not subclass ForwardingHandler must exercise more care in their "get" trap if they want to intercept the this-binding. Most other alternatives make it easier for proxy authors to avoid this issue, but at the expense of making the JS MOP strictly more complex/less intuitive.

You already have my challenge to try to define such a handler.  I'm actually more concerned about inconsistent behavior for both internal (eg, valueOf) and user coded conditional calls.  

Allen 






-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.mozilla.org/pipermail/es-discuss/attachments/20130923/2b8c9300/attachment.html>


More information about the es-discuss mailing list