custom proto arg for Proxy.createFunction?

David Bruant bruant at enseirb-matmeca.fr
Thu Feb 24 04:10:12 PST 2011


Ok... hmm... well...
I misread your initial post. You wanted to enforce the condition on the
argument proto object, not the object returned by Proxy.createFunction.
My apologies, here's my fixed response:

Le 24/02/2011 11:42, David Bruant a écrit :
> Le 24/02/2011 02:32, David Herman a écrit :
>>>> The simple instanceof check seems simpler and reasonably intuitive.
>>> By "hardcoding" p instanceof Function === true
>> I'm not proposing this -- it's already true. Try it out in SpiderMonkey:
>>
>>     js> (Proxy.createFunction({}, function(){}, function(){})) instanceof Function
>>     true
>>
>>> you're breaking your
>>> user expectation of finding the Function.prototype methods ("call",
>>> "apply" or any further addition) in the object.
>> I think I haven't made myself clear. Certainly, users generally expect invariants like:
>>
>>     if (x instanceof y) and (key in y.prototype) then (key in x)
>>     if (y === Object.getPrototypeOf(x)) and (key in y) then (key in x)
>>
>> But proxies *already* break these invariants. It's *already* possible to write a proxy that doesn't have a property that its prototype has. You can do this *both* with Proxy.create(), which lets you provide a prototype but act as though you don't have properties of the prototype, *and* with Proxy.createFunction(), which insists that your proxy is an instanceof Function but again lets you act as though you don't have the properties of Function.prototype.
>>
>> None of this has anything to do with my suggested extension, which is allowing a user-specified prototype to Proxy.createFunction.
>>
>>>>> With your solution, by removing Function.prototype from the chain, proxy
>>>>> functions couldn't be .call()-ed or .apply()-ed
>>>> That's already true, even without my extension:
>>>>
>>>>    js> var proxy = Proxy.createFunction({}, function(){}, function(){})
>>>>    js> proxy.call(this)   
>>>>    typein:11: TypeError: getPropertyDescriptor is not a function
>>> The bug is in your code:
>> No, there's no bug. The point of my code was to demonstrate that it's already possible to break the above invariant.
>>
>> If you want to promote as best practices that people should *strive* to uphold the invariant, even though it isn't enforced by the language, that's fine. But allowing user-specified prototypes for Proxy.createFunction doesn't change this. It's still up to the proxy writer to ensure that they delegate to the prototype, regardless of whether the prototype is Function.prototype or a descendant of Function.prototype.
> This is currently true that it's up to the writer, but is likely to
> become half-false:
> Previously (starting here:
> https://mail.mozilla.org/pipermail/es-discuss/2011-January/012603.html)
> we've been discussing the idea that getPropertyNames and
> getPropertyDescriptor become derived traps and that their default
> behavior would be to climb the prototype chain. This way, by default,
> the prototype delegation occurs, so it wouldn't be up to the proxy
> writer to ensure prototype delegation.
> But the proxy writer can decide to override getPropertyNames and
> getPropertyDescriptor (or any trap that would) anyway and then mess with
> prototype delegation, I agree.
>
>
>>> When you do "proxy.call(this)", the "proxy.call" getter is trapped as
>>> the "get" trap. Since you do not define it (your handler objectis
>>> empty), the default get trap is called (see here :
>>> http://wiki.ecmascript.org/doku.php?id=harmony:proxies#trap_defaults).
>>> In this default get trap, the first thing that is done is a call to
>>> this.getPropertyDescriptor ("this" refers to the handler object which is
>>> empty in your example). And here, the error is thrown by the engine
>>> since handler.getPropertyDescriptor isn't a function because it's undefined.
>> Well, of course! That's my point. Proxies do not force you to respect prototype delegation.
> Ok, I thought you made a mistake.
>
>>> This code is ugly, because my get handler methods assumes that the proxy
>>> object is reachable from the lexical scope which could not be the case
>>> (I could have used the "rec" argument, but that's not very clean). There
>>> is an ongoing discussion to make the proxy object available as an
>>> argument in each trap. This way, the get trap could be rewritten as:
>>> get: function (rec, name, proxy){
>>>    return Object.getPrototypeOf(proxy)[name];
>>>    // Object.getPrototypeOf(proxy) is Function.prototype by definition here
>>> }
>>> This is actually one more argument in the direction of making this happen.
>> That seems like a non sequitur; in what you've written, I don't see any argument against allowing Proxy.createFunction() to accept a user-specified prototype.
>>
>> Again: the whole design of the proxy system *already* requires you to implement the delegation manually if you want to respect the prototype chain. But you don't have to respect the prototype delegation chain. That's true for both Object.create() and Object.createFunction().
>>
>> All I'm proposing is allowing you to specify a descendant of Function.prototype as your prototype link, rather than Function.prototype itself.
> (...)
>
> 4) Make sure that proto contains Function.prototype in its chain and
> throw an error if it isn't the case
That's what you're suggesting from the beginning if I understand well.

>> Either way, it's up to the programmer to decide whether they want to respect prototype delegation in their traps.
> Indeed. Actually, since it's currently up to the programmer to
> re-implement delegation, what are you expecting from choosing your
> prototype object? Can't you just use it in your handler object? I'm just
> talking about currently (current spec state and current FF4 implementation).
> For the longerer term, if, as discussed, getPropertyNames and
> getPropertyDescriptor become derived traps with the suggestion default
> implementation, it completly makes sense to add an additional argument,
> with the still pending issue of how to enforce the result of instanceof
> (I'm actually a fan of the 4th solution).

David


More information about the es-discuss mailing list