Proxies: wrong "receiver" used in default "set" trap

Allen Wirfs-Brock allen at wirfs-brock.com
Wed Dec 19 09:17:04 PST 2012


On Dec 19, 2012, at 2:01 AM, Tom Van Cutsem wrote:

> 2012/12/19 Allen Wirfs-Brock <allen at wirfs-brock.com>
> I think it has to be A, for consistency with [[Call]].  Note that when [[Call]] is directly forwarded to the target, the this value is set to target. It wouldn't be self-consistent if directly forwarded foo.access and foo.method() invocations used different this values.
> 
> Hmm, in the current proxies draft spec, the default [[Call]] behavior does not modify the thisBinding upon forwarding, so:
> 
> var that = {}
> var proxy = Proxy(function() { return this === that; }, {}) // default "apply" trap
> proxy.call(that) // true
> 
> It would be very strange for |this| to be bound to the function object itself. That typically does not make sense.

Yes, sorry about that.  I was think about the contrasting the this value that gets past on a method call on a proxy and I mind farted and looked at [[Call]] when that isn't the issue.

> 
> I assume that by "proxy is the initial receiver", you mean that for a [[SetP]]/[[GetP]] invocation that  SameValue(O,Receiver) is true.  If so, that also seems right to me.  In writjing various [[SetP]]/[[GetP]]/equivalent proxy traps, this test is one I've found that I routine have  to make.  It basically distinguished between the initial application of the operation and  a proto climbing (or other similar delegating) application. 
> 
> Yes, that is what I meant.
> 
> I'm actually surprised that I didn't notice this wrong receiver issue when I incorporated Proxy exotics into the ES6 spec. as I spend a lot of time thinking about what was the correct this value to forward in various situations.  I'm not blissfully happy with the current forwarding model, but I think it is ok as long as we make sure it is completely self consistent.  The situations I was concerned with are similar for [[Call]] when it is directly forward.  If prox.foo() is forwarded so that the foo method is invoked with the proxy's target as the this value then any this.bar() calls within the foo method dispatches through the target rather than prox.  From an OO delegation perspective this feels wrong.  However, it feels ok if you think of direct forward not as a form of object delegation but rather redirection to a completely oindependent object(the target).  In that case, it is very important that all forwarding consistently use the target as the receiver.
> 
> Yes, the behavior here is odd:
> for "direct" method invocations such as proxy.foo(), we want pure forwarding behavior, with |this| bound to the target in the forwarded call.
> for "delegated" method invocations such as Object.create(proxy).foo(), prototype-based inheritance dictates that inside the forwarded foo(), |this| should be bound to the child object.

Yes, this is exactly the issue that caused me to wander down the [[Call]] trail above.

Consider:

let target = {foo() {return this}};
let proxy = Proxy(target, {});

As currently spec'ed.  proxy.foo() is going to return proxy rather than target.

That's because,  proxy.foo evaluates to a Reference whose base is proxy.  Getting the value of the reference does a [[GetP]] that has proxy as both its this value and receiver value.  That is directly forwarded to target (as currently spec'ed: still with proxy as the receiver value), with which returns the function.   We then do a [[Call]] of the function using the base of the Reference (ie, proxy) as the this value.  So, for proxy.foo() we are not getting pure forwarding.

If we make the Option A change that seems right for  [[GetP]]/[[SetP]] then we will have an inconsistency between the this value used for a method invoked as proxy.foo() and a accessor invoked as proxy.bar

This issue arises because method lookup and method invocation is done in two separate steps.  I'm not sure there is an easy fix that doesn't involve introduce a [[CallProperty]] internal method.

Allen

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.mozilla.org/pipermail/es-discuss/attachments/20121219/36625eaa/attachment-0001.html>


More information about the es-discuss mailing list