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

Reply via email to