Ok, so Mark and I briefly discussed the implications of making "getPropertyDescriptor" and "getPropertyNames" derived.
Here's one issue: if you try and write these traps as methods of some sort of "default" handler as we did for the other derived traps (see < http://wiki.ecmascript.org/doku.php?id=harmony:proxies#trap_defaults>) you'll notice that the handler, by default, has no way of referring to the proxy it's intercepting, hence can't get at its prototype and hence can't do the prototype-chain-walk. Now, from an implementation point-of-view, this isn't really a problem since the proxy implementation can make the connection between proxy and handler when the trap is called, and thus can do the prototype-chain-walk. It's just that you can't write it out in Javascript itself. Mark argues that therefore, "getPropertyDescriptor" and "getPropertyNames" are still fundamental. Yet we both agree that providing a default implementation for these 2 traps makes perfect sense. Mark suggested we could classify traps in two different ways: ("optional" vs "mandatory") vs ("fundamental" vs "derived"). In that view, getPropertyDescriptor and getPropertyNames would be optional and fundamental. All other traps would be either (fundamental & mandatory) or (derived & optional). I think that for developers, really the only distinction that matters is "optional" vs "mandatory". The "fundamental" vs "derived" distinction helps to clarify things for us spec. readers/writers. While writing this, I also thought of another potential solution: we could choose to pass the proxy as an additional argument to the traps. Then the default implementation of getPropertyDescriptor could be written in Javascript as follows (adapting David's code): // currently, this trap only takes the 'name' param getPropertyDescriptor: function(proxy, name) { var objectToInspect; var result; for(objectToInspect = proxy; objectToInspect !== null; objectToInspect = Object.getPrototypeOf(objectToInspect)) { result = Object.getOwnPropertyDescriptor(objectToInspect, name); if (result !== undefined) { return result; } } return undefined; } Cheers, Tom 2011/1/24 Tom Van Cutsem <[email protected]> > David, > > Your intuition of what constitutes a fundamental vs. a derived trap is > correct. Strictly speaking, the Proxy API could do with just the fundamental > traps. The motivation for providing the optional derived traps was that > overriding derived traps often allows proxy implementors to implement the > operation more efficiently (usually with less object allocations). > > As for your suggestion of turning 'getPropertyNames' and > 'getPropertyDescriptor' into derived traps: I think you're correct. We could > specify getPropertyNames and getPropertyDescriptor in terms of their "own" > siblings + a prototype-chain-walk. > > I recall a discussion with Mark where this issue was briefly discussed > before. At that time, I was concerned by the fact that you could equally > well define getOwnPropertyDescriptor as the derived trap, in terms of > getPropertyDescriptor + getOwnPropertyNames, as follows: > > getOwnPropertyDescriptor: function(name) { > var desc = this.getPropertyDescriptor(name); > var ownnames = this.getOwnPropertyNames(); > if (ownnames.indexOf(name) !== -1) > return desc; > else > return undefined; > } > > But applying the principle of minimizing the amount of allocations in > default trap implementations, your definition is strictly the better one. > > I'm in favor of any change that can minimize the amount of fundamental > traps, so I'm in favor of adopting your change. Maybe Mark still recalls > reasons for why these traps were categorized as fundamental traps in the > first place. > > Cheers, > Tom > > 2011/1/23 Brendan Eich <[email protected]> > > I think David has a point. The fundamental vs. derived distinction is, as I >> understand it, what Mark wrote recently, and David's application of it is >> sound (we do that prototype-walk with shadowing "duplicate removal" when >> starting a for-in loop in SpiderMonkey). Tom should weigh in. >> >> But proxies have a proto chain for instanceof and good old prototype-based >> delegation purposes, even though their traps could ignore the proto >> parameter. The instanceof operator will not, and note how there is no >> getPrototypeOf trap, either. >> >> This is a feature. I asked early on in the development of proxies whether >> the alternative, of putting the proto-chain walk "on the outside" of the >> proxy's handler traps was considered, and Mark pointed out the obvious: that >> doing so is strictly less flexible for cases where a proxy wants to do >> something different. >> >> But this greater-flexibility design decision does not mean the universal, >> object -invariant (ignoring mutable __proto__) instanceof and getPrototypeOf >> (and ES3's isPrototypeOf) relations should be outside of a proxy's control. >> The Proxy.create proto parameter is the way to control those relations, for >> the life of a given proxy, and modulo property lookup trap freedom to do >> other things than just delegate up the proto chain. >> >> /be >> >> On Jan 23, 2011, at 8:43 AM, François REMY wrote: >> >> Moreover, should a Proxy really have a prototype ? >> I mean, what’s the point about having a prototype, since the “get” method >> can return everything you would like for any property ? >> >> I think getProtototypeOf should be defined as a new trap. And its default >> behaviour should be to return null (or Object.prototype, but I think null is >> the intented behavior of a proxy). >> >> On the other hand, overriding getPropertyNames should not be allowed. >> getPropertyNames should *always* return the concatenation of the properties >> returned by getOwnPropertyNames() and by >> getPrototypeOf(this).getPropertyNames(). It makes no sense otherwhise. >> >> I understand that we may want to redefine the way an ECMAScript Object can >> handle the native commands, but I’m strongly against anything that can >> conduce to illogical results (if there’s not an use case that justify it, >> naturally). The definition of getPropertyNames is clear and being able to >> redefine it locally seems me wrong. A proxy can modify is own behavior, not >> the behavior of the ES engine. Being able to have getPropertyNames and >> getOwnPropertyNames returning incompatible results is somewhat hurting me. >> Is there any reason we should allow that ? Any use case ? >> >> I’m issuing the same concerns for the “has” trap. It think it should not >> be a trap. It should always return hasOwn(key) || prototype.has(key). Each >> one of hasOwn and prototype can be tuned by the proxy, but not the “has” >> itself. We’re not removing features, but we prevent bad usage of it. >> Whatever the user code do, the ‘has’ behavior will stay logical. >> >> Another thing I don’t quite understand is the difference between “keys” >> and “enumerate”. If there’s no strong difference, it should be the same trap >> (same logic: enumerate should return the concatenation of this.keys and >> this.prototype.keys). Having two different but similar traps will cause >> confusion. Maybe there’s a need for this difference however. I just didn’t >> understand why such a difference should exist, but at least I see more >> possible usages than the first three traps I “contested”. >> >> Anyway, if we should retain only one thing from the discussions we already >> have seen on the Proxy hub, is that it’s a great feature, but one that still >> needs some work before implementation ;-) >> >> Regards, >> François >> >> *From:* David Bruant <[email protected]> >> *Sent:* Sunday, January 23, 2011 4:24 PM >> *To:* es-discuss <[email protected]> >> *Cc:* Mark S. Miller <[email protected]> >> *Subject:* [ES Harmony Proxies] Fundamental trap definition >> >> Hi, >> >> I am wondering if getPropertyDescriptor and getPropertyNames fundamental >> traps shouldn't rather be derived traps since they could have a pretty >> straightforward default implementation. >> One implementation of getPropertyNames could be : >> -------------------------- >> Object.getPropertyNames = function(o){ >> var objectToInspect; >> var result = []; >> >> for(objectToInspect = o; >> objectToInspect !== null; >> objectToInspect = Object.getPrototypeOf(objectToInspect)) >> { >> result = >> result.concat(Object.getOwnPropertyNames(objectToInspect)); >> } >> >> return result.removeDuplicates(); // the removeDuplicates method is >> made up, but you get the point >> } >> -------------------------- >> This seem to fit the proposal ( >> http://wiki.ecmascript.org/doku.php?id=harmony:extended_object_api&s=getpropertydescriptor) >> expectations). This could be also the default getPropertyNames trap >> implementation. >> >> I haven't really seen a strong definition of what fundamental traps are in >> the proposal. On Mark Miller's e-mail ( >> https://mail.mozilla.org/pipermail/es-discuss/2011-January/012601.html) >> is written: >> [a trap is fundamental if] there is no coherent default behavior to fall >> back to that would be defined in terms of the remaining traps. (please tell >> me if I misinterpret what you meant) >> If we're going with this definition, then getPropertyDescriptor and >> getPropertyNames should probably be derived traps since they can clearly be >> defined thanks to other traps (respectively getOwnPropertyDescriptor and >> getOwnPropertyNames as I showed above) which seems to be coherent >> fallback behavior. >> Instead of a formal definition, this could be a rational for deciding what >> is a fundamental trap and what isn't. >> >> In the 5 remaining traps (getOwnPropertyDescriptor, getOwnPropertyNames, >> defineProperty, delete, fix), I don't see any that could be defined thanks >> to the others. They seem to be also the fundamental actions that one can >> perform on a single object: >> Property-wise: >> - create/configure a property (defineProperty) >> - delete a property (delete) >> - retrieve a property (getOwnPropertyDescriptor. Can be used to separate >> the create and configure cases of defineProperty) >> Property-set-wise: >> - retrieve the property set (getOwnPropertyNames. More can be found later >> on each property with getOwnPropertyDescriptor) >> - prevent further extension (and optional reconfigurations for seal and >> freeze)(fix) >> The prototype can be retrieved thanks to Object.getPrototypeOf (which >> cannot be trapped for consistency purposes) and all actions can be performed >> by climbing the prototype chain. >> >> Any thoughts on the fundamental trap definition? >> Or on the idea of turning getPropertyDescriptor and getPropertyNames into >> derived traps with the suggested definition? >> >> David >> >> ------------------------------ >> _______________________________________________ >> 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 >> >> >> >> _______________________________________________ >> 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

