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.

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. 

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.

If you really want to [[Call]] a target method with the proxy as the this value 
or do the equivalent for [[SetP]]//[[GetP]] you can do it by providing a hander 
that does what you want rather than depending upon direct forwarding.

Allen

 

On Dec 18, 2012, at 1:56 PM, Tom Van Cutsem wrote:

> Hi,
> 
> Someone recently reported an issue [1] while using my harmony-reflect shim 
> for direct proxies. The fix probably requires a change in the proxy 
> specification. I'm unsure how to resolve it, so I thought I'd bring it to the 
> list.
> 
> The issue is as follows:
> 
> consider a proxy with an empty handler:
> var proxy = Proxy(target, {});
> 
> now consider assigning a property to the proxy:
> proxy.foo = 42
> 
> This triggers the proxy's "set" trap, but since the handler does not define 
> this trap, the default behavior is to forward the assignment to the target.
> 
> As currently specified, the intercepted assignment is forwarded as:
> 
> Reflect.set(target, 'foo', 42, proxy)
> 
> where 'proxy' is used as the "initial receiver" of the property assignment.
> 
> This fourth "receiver" argument matters for two reasons:
> 1) if 'target' defines or inherits 'foo' as an accessor property, inside that 
> accessor, |this| will point to that receiver argument.
> 2) if receiver !== target, then Reflect.set will *add* a new data property to 
> receiver, rather than *update* an existing data property on the target.
> 
> Currently, for an assignment as shown above, the proxy itself is passed as 
> the fourth 'receiver' argument. Thus:
> 1) inside triggered accessors, |this| will refer to the proxy, not to the 
> target. This is acceptable.
> 2) since proxy !== target, Reflect.set will try to *add* data properties to 
> 'If you want to   ddasfdasfasdfafasfasffsff
> 
> I see two solutions, but can't decide on which is better. There may be better 
> solutions altogether.
> 
> Option A:
> change the default forwarding behavior of the "set" trap to:
> 
> if the proxy is the initial receiver of the property assignment, then
>   return Reflect.set(target, name, val, target)
> else
>   return Reflect.set(target, name, val, receiver)
> 
> If the initial receiver is an object that delegates to a proxy, the proxy 
> won't change the receiver upon forwarding, in order to not interfere with 
> prototype inheritance.
> 
> This solution fixes point 2) since Reflect.set is no longer confused about 
> the proxy.
> Re. point 1), the |this|-binding inside forwarded accessors will now refer to 
> the target object itself, which I find equally acceptable.
> 
> For reasons of symmetry, if we go this route, we probably need to change the 
> default forwarding behavior of "get" in a similar way. Point 2) does not come 
> up in this case, but Point 1) does. We probably want the rules for 
> |this|-binding in forwarded getters to be consistent with setters.
> 
> Option B:
> Address point 2) directly by changing the test that determines property 
> addition versus property update inside Reflect.set (i.e. the [[SetP]] 
> internal method of objects) so that the algorithm no longer tests whether 
> target === receiver, but rather whether target === receiver || receiver is a 
> proxy for target.
> 
> This solves the issue at hand, although it feels like a more ad hoc solution.
> 
> 
> Another way of looking at things is that the Reflect.set (or [[SetP]]) 
> algorithm currently assumes that the "receiver" argument is either the target 
> object itself, or otherwise an object that directly or indirectly inherits 
> from the target object. If this assumption is violated, strange behavior can 
> ensue. In the above example, the proxy passed in as the "receiver" argument 
> is neither the target object nor an object that inherits from it, hence the 
> strange behavior.
> 
> Cheers,
> Tom
> 
> [1] https://github.com/tvcutsem/harmony-reflect/issues/11 
> _______________________________________________
> es-discuss mailing list
> es-discuss@mozilla.org
> https://mail.mozilla.org/listinfo/es-discuss

_______________________________________________
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss

Reply via email to