On Dec 2, 2012, at 11:40 AM, Tom Van Cutsem wrote: > 2012/12/2 Mark S. Miller <[email protected]> > I think we can rescue around wrapping. I'll call this approach "opaque > around wrapping". The idea is that the proxy passes into the handler > trap a proxy-generated no-argument function (a thunk) called "action". > > Interesting. I had thought of a similar approach, but hadn't pursued it > because I thought allocating a thunk per trap invocation would be deemed too > expensive. I'll go ahead and sketch the design, which I think corresponds > closely with your approach B)
This is my first reaction too. I want Proxies to be lightweight enough so they really can be used be used for things like self hosting built-ins and web API objects. The need to create an pass in a action thunk on each trap calls initially feels too expensive. But that is only a first reaction. Perhaps the expense really isn't that great. Or perhaps a lot of the cases where I have assumed the Proxies would be needed could be handled by lightweight mechanisms such such as the @elementGet/@elementSet hooks described in http://wiki.ecmascript.org/doku.php?id=strawman:object_model_reformation (see Implementing Built-inArray without Proxy and Rationalizing DOM HTMLCollections examples) Allen > > First, from the point-of-view of the trap implementor, things would work as > follows (I show the "defineProperty" trap only as an example) > > All traps take an extra thunk as last argument, which I will name "forward", > since calling that thunk has the effect of forwarding the operation to the > target, returning the original result. > > defineProperty: function(target, name, desc, forward) { > // before > var result = forward(); > // after > return result; > } > > Now, from the point-of-view of the proxy implementation, how is the above > trap called? > > // in the proxy, intercepting Object.defineProperty(proxy, name, desc) > // where proxy = Proxy(target, handler) > var result = Uninitialized; > var thunk = function() { > if (result === Disabled) throw new Error("can only call forward() during > trap invocation"); > if (result !== Uninitialized) throw new Error("forward() can be called only > once"); > result = Reflect.defineProperty(target, name, desc); // forward to target > return result; > }; > var trapResult = handler["defineProperty"].call(handler, target, name, desc, > thunk); > if (result !== Uninitialized && result === trapResult) return result; // no > invariant checks when original result is returned > if (result === Uninitialized || result !== trapResult) { /* do invariant > checks */ ; return result; } > result = Disabled; // ensures one cannot call forward() outside of dynamic > extent of the invocation > > I'll answer your questions for the above design: > > Open questions that take us to different design possibilities: > 1) what happens if the trap does not call action? > Invariant checks are performed on the returned result. > > 2) what happens if the trap calls action more than once? > An exception is thrown. > > 3) do actions ever return anything, in case the trap wants to pay > attention to it? > Yes, it returns the value of the operation, applied to the target. > > 4) are there any return values from the trap that the proxy would pay > attention to? > Yes. If the trap returns the original result, it doesn't do any extra checks. > Otherwise it does. > > 5) if the original operation performed by action throws, should the > action still just return to the trap normally? > A thrown exception would escape and abort the entire operation, unless the > trap wraps the call to forward() in a try-catch block. > > 6) what happens if the trap throws rather that returning? > Thrown exceptions are always propagated to clients. > > I prefer #A to #B as it gains the full benefits of simplifying the > overall spec and implementation. However, #B still seems better than > current direct proxies, as the normal case gets target-maintenance and > invariant checking for free. > > I agree that #B doesn't really simplify anything in the spec (the invariant > checks are still there sometimes). > I'm not sure if it is inherently better than the current design though: we > gain performance in terms of avoiding invariant checks, but we lose > performance by having to allocate a per-call thunk, + the API becomes more > complex (an additional parameter to every trap) > > I do think that passing an action or "forward()" thunk to a trap as extra > argument beats David's proposed "throw ForwardToTarget" trick in terms of > elegance and usability (maybe not in terms of performance). > > Cheers, > Tom > _______________________________________________ > es-discuss mailing list > [email protected] > https://mail.mozilla.org/listinfo/es-discuss
_______________________________________________ es-discuss mailing list [email protected] https://mail.mozilla.org/listinfo/es-discuss

