Re: Proxy forwarding handlers and accessor properties

2011-06-19 Thread Tom Van Cutsem
I agree with all of David's points. I wonder though: would it make more
sense if we'd spec. the get trap of Proxy.Handler as:

  get: function(name, proxy) {
let val = this.target[name];
return typeof val === function ? val.bind(this.target) : val;
  }

Then both method  accessor invocation bind |this| to the target.

It's hard to say what the expected default behavior is for the default
forwarding handler: should it leave |this| bound to the proxy or to the
target when forwarding a method invocation? As David mentioned, programmers
can always implement either, but what should be the default? Creating a new
bound function per |get| invocation may be expensive though. Also, treating
a property bound to a function as a method is an imperfect heuristic.

Cheers,
Tom

2011/6/17 David Bruant david.bru...@labri.fr

 Le 17/06/2011 08:42, David Flanagan a écrit :

  On 6/16/11 5:20 PM, David Bruant wrote:

 Le 17/06/2011 01:54, David Flanagan a écrit :


 // When we create a proxy with a forwarding handler, though, the this
 value
 // is different in the two cases.
 var handler = {
 target: o,
 get: function(receiver, name) {
 return this.target[name];  // Same as
 Proxy.Handler.prototype.get
 }
 }

 If you get rid of the get trap (you need a getOwnPropertyDescriptor
 trap though), the default get (derived) trap will be called instead and
 basically do what you do afterward (call to getOwnPropertyDescriptor
 trap which will call Object.**getOwnPropertyDescriptor(this.**target,
 name)+d.get.call(receiver)). The 'this' binding is performed by the
 engine (with the receiver as value) after the property descriptor has
 been returned (as explained in strawman:proxy_drop_receiver).

  Thanks.  I didn't realize that the default get behavior was to do what I
 put in my second handler.

 Yep. http://wiki.ecmascript.org/**doku.php?id=harmony:proxies#**
 trap_defaultshttp://wiki.ecmascript.org/doku.php?id=harmony:proxies#trap_defaults
 Besides type checking, the code is the same than yours for the get trap.
 In a way, it's reassuring that people experimenting like you do reach the
 same solution to the same problem independently.


  Still, my basic question remains, though: is it a bug that a forwarding
 proxy created with Proxy.Handler behaves differently in this way (this value
 in methods is different than the this value for accessors) than the object
 to which it forwards?

 I do not think it's a bug. What happens with your code is coherent with
 ECMAScript (and apparently, the JS implementation is consistent with that
 too).
 I think that a more important question is: can you achieve what you want
 (giving the impression that this is the same for both getters/setters and
 methods) with the current proxy API?. If so, is it natural or is it a
 hack?
 Apparently, you can achieve what you want and my opinion is that the
 solution is natural (using the derived trap default behavior). Removing a
 trap to achieve your goal may sound not natural, but strawman:derived_traps_
 **forwarding_handler seems to be a decent solution for that.



  (Originally I had a second question about the proposed removal of the
 receiver argument, but now I understand that that strawman is contingent on
 the addition of a proxy argument to the handler methods, so let's disregard
 that second question...)

 Yes, I'm sorry, I should have mentionned that. I tend to consider this
 strawman as already accepted since it sounds so natural to me and has found
 several justifications on es-discuss. It is however true it still needs to
 be accepted (July TC-39 meeting, hopefully?) and SpiderMonkey will need to
 be adjusted consequently.


 David
 __**_
 es-discuss mailing list
 es-discuss@mozilla.org
 https://mail.mozilla.org/**listinfo/es-discusshttps://mail.mozilla.org/listinfo/es-discuss

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


Proxy forwarding handlers and accessor properties

2011-06-16 Thread David Flanagan
With ordinary objects, methods and property getter functions are both 
invoked on the object itself.  If this object is proxied with 
Proxy.Handler, however, the property getter function will be invoked on 
the original object and the method will be invoked on the proxy object.  
The code below demonstrates.


I find this surprising, though I'm not sure whether it constitutes a bug 
in Proxy.Handler.  I do think it is at least a reason why the receiver 
argument to get() is necessary and should not be removed as proposed by 
http://wiki.ecmascript.org/doku.php?id=strawman:proxy_drop_receiver


The code that demonstrates this is below.  It runs in the current 
Firefox Aurora. I have actually been affected by this issue when the 
proxy object is stored in a WeakMap but the object it is forwarding to 
is not in the WeakMap.


David Flanagan


if (this.console) print = console.log.bind(console);

// An object with an accessor property and a method.
var o = {
get property() { return map.get(this); },
method: function() { return map.get(this); }
};

var map = new WeakMap();
map.set(o, o);

// Both the getter function and method are invoked on o
print(o.property); // prints o
print(o.method()); // prints o

// This works for inherited properties and methods, too
var p = Object.create(o);
map.set(p, p);
print(p.property);// prints p
print(p.method());// ditto


// When we create a proxy with a forwarding handler, though, the this value
// is different in the two cases.
var handler = {
target: o,
get: function(receiver, name) {
return this.target[name];  // Same as Proxy.Handler.prototype.get
}
}

var q = Proxy.create(handler);
map.set(q, q);
print(q.property);   // Prints o
print(q.method());   // Prints q

// In order to invoke the getter function on the same object as the method
// we have to go to more trouble and use code that is probably much slower.
// And, we need that first receiver argument.
var handler2 = {
target: o,
get: function(receiver, name) {
var d = Object.getOwnPropertyDescriptor(this.target, name);
if (d.value) return d.value;
else return d.get.call(receiver);
}
};

var r = Proxy.create(handler2);
map.set(r, r);
print(r.property);   // Prints r
print(r.method());   // Prints r


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