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

Reply via email to