Le 04/04/2011 17:08, Tom Van Cutsem a écrit : > Hi, > > 2011/3/31 David Bruant <[email protected] > <mailto:[email protected]>> > > Hi, > > First, I'd like to say that I'm glad proxy-related issues have > been discussed during the last TC-39 meeting and that all have > found an agreement. > > Then I have a something to say on > http://wiki.ecmascript.org/doku.php?id=strawman:handler_access_to_proxy > Quoting relevant parts: > "Andreas: experimenting with DOM wrappers. All prototype-climbing > traps require access to the receiver object (which is not > necessarily the proxy object), not just the get/set traps. The get > and set trap may want access to both the receiver and the proxy. " > "Current consensus: > * add receiver as a first argument to all prototype-climbing traps > (get, set, has, getPropertyNames, getPropertyDescriptor traps)" > > The intention I understand is that these proto-climbing traps > should first be applied to the own layer (or rather, their "own" > equivalent) then be applied recursively while climbing the > prototype chain. > However, I think that with current ES5 internal method definitions > and proxies semantics > (http://wiki.ecmascript.org/doku.php?id=harmony:proxies_semantics), this > doesn't work as the intention goes. For instance, [[Get]] (ES5 > 8.12.3) uses [[GetProperty]] and calls [[GetProperty]] recursively > on the prototype object instead of the [[Get]] internal method. > And currently (it was the case before the meeting. I'm just > realizing now), semantics of [[GetProperty]] is to return undefined. > Similar issues goes with current "has" trap and [[HasProperty]] > internal methods which delegates inheritance responsibility to > [[GetProperty]] (back to previous problem). > > However, getPropertyNames and getPropertyDescriptor traps, > recently "promoted" as derived traps are still underspecified. > Interestingly, the current implementation > (http://wiki.ecmascript.org/doku.php?id=strawman:proxy_derived_traps) > isn't recursive, but iterative. This is inconsistent with the > current model and should certainly be redefined as a recursive > function: > --- > getPropertyDescriptor: function(receiver, name, proxy) { > var pd = Object.getOwnPropertyDescriptor(receiver, name, proxy); > var proto = Object.getPrototypeOf(proxy); > if(proto === null || pd !== undefined) > return pd; > return Object.getPropertyDescriptor(proto); // recursive > version. receiver is passed in some way (?) > } > --- > > > I think you're right. The spec uses recursion, so a proxy higher up > the inheritance chain could terminate the lookup early. > > I also don't see how the original object to which > Object.getPropertyDescriptor was applied could be passed up the chain. > I also don't see the need for it, other than perhaps calling > |bind(receiver)| on the found property descriptor's value, get or set > attribute? I don't think it's necessary for the "value". --- var p = Proxy.create(h); p.f(); // in the meta-level means: h.get(p, 'f').apply(p); --- But the .apply(p) is handled by the engine after the h.get call. So the "get" trap doesn't need the receiver to bind it for the function call. I agree it does need it for set/get anyway.
> > > I'd like to remind that if Object.getPropertyDescriptorisn't a > native function with a native underlying internal method, but a > monkey patch, it will not call a proxy trap (maybe this should be > addressed?). > > > There's a Harmony proposal that proposes adding > Object.getPropertyDescriptor as a new built-in on Object for precisely > this > reason: <http://wiki.ecmascript.org/doku.php?id=harmony:extended_object_api> I agree. The point I wanted to see addressed is when ES engines only partially natively implement the Object introspection API. Currently, Safari 5 doesn't implement preventExtension/seal/freeze. No browser implement getPropertyDescriptor and getPropertyNames (so Object.getPropertyDescriptor wouldn't be trapped if monkey-patched). If all browsers implement proxies now, the same code will reveal inconsistencies if browsers have different stage of Object.* implementation. Same thing if new traps are created afterward. It's very unlikely that all browser will implement the relevant Object.* method at the same time. Maybe we should investigate something like Proxy.trap(o, name, arguments). Example: ---- if(typeof Object.getPropertyDescriptor != "function"){ Object.getPropertyDescriptor = function(o){ if(Proxy.isProxy(o)){ // There is a need to be able to discriminate return Proxy.trap(o, "getPropertyDescriptor"); // call the trap manually, because the native code cannot do it. /* For seal/freeze, the trap name has nothing to do with the method name and no 1:1 mapping can be done, hence the string argument */ } else{ // code for regular object } }; } ---- This has downsides and as always, I'm not going to fight for this particular syntax, but I think that there is a need for a mechanism for developers to compensate browsers uneven implementations. In a world where all browsers would all move at the same pace and older browsers market share were dropping as soon as a new version was showing up, we wouldn't need such a mechanism, but I don't think we should assume living in such a world. > > > > The iterative model differs from the recursive one in a way that > the engine is in control of making sure all layers are > well-traversed and not "hijacked" by one particular layer. This is > actually the idea I called "inheritance-safe proxies" > (https://mail.mozilla.org/pipermail/es-discuss/2011-March/013366.html). > > I am wondering if by providing both proxy and receiver to all > proto-climbing methods, we're not providing too much power to > proxies. Let's imagine the following object with prototype chain: > o --> a --> b --> null. > a is a proxy and o and b are regular objects (or even proxies, it > doesn't really matter with the current model). First, with the > current model, since when a call is trapped, inheritance and > actual prototype can be faked, a has the power of denying b and > messing up with be through Object.getPrototypeOf. Now, if a gets > access to 'receiver', it means it can mess up with o. Aren't we > providing too much power to a? > > > Proxies would always be able to "deny" lookup proceeding to their > prototype, since you could implement a proxy that pretends to have all > possible properties as own properties. But granted: if the handler > never gets access to the proxy, then I don't think it can otherwise > influence the proxy's prototype. > > As for |a| getting access to |o|, it needs this to faithfully emulate > accessor properties (see below). > > > The more I think about it, the more I question the idea of > provinding receiver as an argument to proto-climbing traps. What > was the initial rationale behind it? I understand that it is > different from proxy, but is it necessary? What are the use cases > that require it? > > > For the get and set traps, a proxy needs the original |receiver| as > the |this|-binding when calling the get/set functions of accessor > properties. Cf. their use in the default implementations of |get| and > |set| here: > <http://wiki.ecmascript.org/doku.php?id=harmony:proxies#trap_defaults> You are perfectly right. I'm not really happy with the idea of providing receiver as an argument to traps, but I don't see how get and set could be implemented otherwise. > I'm not sure why it's needed in the other prototype-climbing traps > (getPropertyDescriptor, getPropertyNames, has, enumerate). Perhaps > Andreas can explain. > > Cheers, > Tom David
_______________________________________________ es-discuss mailing list [email protected] https://mail.mozilla.org/listinfo/es-discuss

