On Dec 20, 2012, at 2:21 AM, Tom Van Cutsem wrote:

> 2012/12/19 Allen Wirfs-Brock <al...@wirfs-brock.com>
> 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
> 
> To clarify, if we apply the fix to [[SetP]] described in my previous message, 
> the following remains the default forwarding behavior of proxies:
> 
> If target.foo is a method:
> proxy.foo() will call target.foo() with |this| bound to the proxy (i.e. 
> Lieberman-style delegation)
> 
> If target.bar is an accessor:
> proxy.foo will call the target.foo getter with |this| bound to the proxy 
> (delegation)
> proxy.foo = 42 will call the target.foo setter with |this| bound to the proxy 
> (delegation)
> 
> If target.baz is a writable data property
> proxy.baz = 42 will eventually call Object.defineProperty(proxy, 'baz', 
> {value:42})
> (and *not* Object.defineProperty(proxy, 'baz', 
> {value:42,enumerable:true,writable:true,configurable:true}) as it did 
> previously)
> This behavior is consistent with the method and accessor case: in all cases, 
> the target delegates back to the proxy.

This is actually essential to maintaining ES5 default semantics because 
{value:42} and {value: 42, enumerable:true,writable:true,configurable:true} 
have quite different meanings to the ordinary [[DefineOwnProperty]].

It is equally important that if target.baz does not exist that 
[[DefineOwnProperty]] is called on proxy with with the full  {value: 42, 
enumerable:true,writable:true,configurable:true} descriptor to ensure that the 
new property gets created using the "crated by assignment" attributes rather 
than the [[DefineOwnProperty]] defaults.

> 
> This bears repeating: the above are only defaults, and proxy authors are free 
> to change the policy by actually implementing traps and taking control.
> 
> One thing that I learned from all this is that it's simpler to think of the 
> proxy as *delegating* (as opposed to forwarding) to its target by default. 
> And under the semantics of invoke = get + apply, that is actually the 
> simplest option.

Yes, this is the best way I have found to think about them and I've been 
patiently waiting for you to see the light :-)   However, a corollary is that 
most  internal method calls within derived internal methods/traps need to 
delegate back to the original "receiver".  In some cases, we don't provide the 
original receiver as an extra argument, so it isn't available to do this.

A quick scan of the ordinary internal method suggests that we may have this 
problem for [[Delete]], [[Enumerate]], [[Keys]], and [[GetOwnProertyKeys]].

More generally, I would argue that all Proxy traps (and the corresponding 
Reflect functions) potentially need access to the original "receiver".  We 
don't know what somebody is going to do in such traps and they well need to 
call back to the original receiver for the same sort of consistency issues we 
have encountered with  [[SetP]].  this is particularly apparent if you think 
multiple levels of proxies chained through their target slots. 

This is subtle and maybe we can slip by without addressing it.  But a 
consistent application of delegation semantics would seem to require it.

Delete 






> 
> Cheers,
> Tom

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

Reply via email to