On Sep 23, 2013, at 3:50 PM, Brendan Eich wrote:

>> Allen Wirfs-Brock <mailto:[email protected]>
>> September 23, 2013 3:06 PM
>> 
>> It's a matter of internal vs external consistency. The implementor of a 
>> Proxy handler needs to internally consistently implement the 'get', 'set', 
>> 'has', 'invoke', etc. traps in order to manifest an object that exhibits the 
>> normally expected object semantics. But there is no fool proof (I contend) 
>> way for the proxy implementor to achieve 'invoke' consistency with 
>> 'get+F.p.call
> 
> Now it depends on what you mean by "fool proof".

Takes into account dynamically added properties (particularly inherited), 
[[Prototype]] mutation, subclassing,etc.

>> 
>> JS programmer have been trained that:
>> 
>> obj.m(args)
>> 
>> is equivalent to:
>> 
>> let f = obj.m;
>> f.call(obj, args)
>> 
>> Sometimes they place additional code between the property access and the 
>> call. That code might make the call conditional. It might memorize f and obj 
>> in order to defer the call to an arbitrary point in the future.
>> 
>> Prior to proxies this was always valid because the semantics of both, at the 
>> MOP level were: f = obj.[[Get]]("m"); f.[[Call]](obj,args). But with proxies 
>> and [[Invoke]], this equivalent is no longer the case.
> 
> Vacuously true, and why we resisted invoke.
> 
>> And with the current definition of F.p.call/apply there is nothing that the 
>> client code can do to reestablish the consistency.
> 
> To use either F.p.call or .apply, you must do obj.[[Get]]("m"). For function 
> objects, [[Call]] is well-specified and what F.p.{c,a} use.
> 
> For proxies, we need something akin to [[Call]]. Is that the point of 
> [[InvokeFunction]]?

Exactly.  [[InvokeFunction]] is the Proxy this aware version of [[Call]]. 

Rather than obj.m(args) turning into obj.[[Invoke]]("m",args) where [[Invoke]] 
internally does [[Get]]+[[Call]] I'm suggesting that  turns into:
       f = obj.[[Get]]("m")
       obj.[[InvokeFunction]](f,args)

(I've left out the extra Receiver parameters that [[Get]], [[Invoke]], and 
[[InvokeFunction]] all can accept.)

[[Invoke]] would go away and the call operator would simply be implemented as 
[[Get]]+[[InvokeFunction]].

In addition, F.p.call/apply would also use [[InvokeFunction]] instead of 
[[Call]] whenever the passed this value is a Proxy.

> 
>> This can be fixed, if obj.m(args) has the semantics of 
>> [[Get]]+[[InvokeFunction]] and F.p.call/apply also uses [[InvokeFunction]] 
>> (noting that is the vast majority of cases [[InvokeFunction]] is exactly the 
>> same as [[Call]].
> 
> Ok, but then Tom asked whether function objects targeted by direct proxies 
> having their [[Call]] overridden was a problem?

Ultimately [[InvokeFunction]] performs a [[Call]] on some function object.  
[[InvokeFunction]] doesn't replace [[Call]] as the primitive function 
invocation hook. 

> 
>> The JS programmers expected equivalence is maintained yet transparent 
>> proxies still have an opportunity to do forward of this values.
>> 
>> BTW, it also restore left to right evaluation of the call operator which 
>> regressed when the call operator was implemented using [[Invoke]].
> 
> If you can rename [[InvokeFunction]] to [[Invoke]] so my head stops 
> exploding, I think we have a deal. But need Tom on board.

Yes, I want to do that renaming.  But for now we are still talking about the 
differences between [[Invoke]] and [[InvokeFunction]] so I can't do the 
renaming yet.  But a key point is that only one of them ends up in the spec. 
and whichever it is will be named [[Invoke]].

Allen

_______________________________________________
es-discuss mailing list
[email protected]
https://mail.mozilla.org/listinfo/es-discuss

Reply via email to