custom proto arg for Proxy.createFunction?

Lasse Reichstein reichsteinatwork at gmail.com
Fri Feb 25 05:41:07 PST 2011


On Wed, 23 Feb 2011 23:41:00 +0100, David Bruant  
<bruant at enseirb-matmeca.fr> wrote:

> Le 23/02/2011 23:26, David Herman a écrit :
>> I've been working on a prototype implementation of the binary data spec  
>> in pure JS (implemented via typed arrays) and I've been bitten by the  
>> lack of a standard mechanism for subclassing Function.
>>
>> I'm using proxies for the implementation, and Proxy.createFunction  
>> doesn't let me specify a custom prototype. Now, I can understand that  
>> this preserves the existing property of the language that the only  
>> callable things are either regexps or descendants of Function. But we  
>> could extend the proxy API to allow custom functions with  
>> user-specified prototypes and still preserve this property:
>>
>>     Proxy.createFunction(handler, callTrap[, constructTrap[, proto]])
>>
>> The proto argument would default to the original value of  
>> Function.prototype [1]. But if the user provides a prototype, the  
>> library could enforce that proto instanceof Function [2]. This way we  
>> would preserve the invariant that for any callable value v, either v is  
>> a regexp or (typeof v === "function" && v instanceof Function).

As long as __proto__ is writable, that can be changed later anyway.
If we get rid of writable __proto__, then it would be an invariant.

I'm not sure why it's important that all Callable objects need to have
Function.prototype in their prototype chain, though. If it's in order to
detect that an object can be called, we could have Object.isCallable(o)
instead.

> With your optional argument, I see a second solution that could be
> consistent. The prototype chain could contain the provided prototype
> then Function.prototype ("obj --> proto --> Function.prototype -->
> null"  as opposed to your proposition which is: "obj --> proto --> null"
> ).

As I read it, that's not what's proposed. Remember that any object has
a prototype chain, so the supplied "proto" could already have the prototype
chain proto->Function.prototype->Object.prototype->null.
At least, Function.prototype will have Object.prototype as prototype, so
it shouldn't be followed by null.

> Hence, there would be no need to enforce anything: instanceof would
> naturally find Function.prototype in the chain and function proxies
> would still be functions.

There is no good way to add Function.prototype to the prototype chain
of "proto" (that would need to change proto's prototype chain, which could
cause other uses of it to break), and also no good way to add "proto" to  
the
prototype chain of Function.prototype.

I think the best you can do is to require Function.prototoype to be in the
prototype chain of "proto", if you want to ensure that all callables are  
Functions.


>> Maciej has also suggested a Function.create(...) API for more  
>> lightweight creation of function subtypes. This would strengthen the  
>> argument for allowing Proxy.createFunction to specify a prototype,  
>> since Proxy.createFunction() ought to be able to do anything  
>> Function.create() can do.
> I'm actually starting to think that this would be a good idea and could
> be applied to other things. Here
> (http://perfectionkills.com/how-ecmascript-5-still-does-not-allow-to-subclass-an-array/)
> is a complain of Arrays which cannot be subclassed. A decent solution
> for that could be to have a Array.create(proto) method which would
> create an array with the prototype chain "myArray --> proto -->
> Array.prototype --> null". It could solve all the problems at a time.

Agree. For consistency, there should also be Date.create (I've seen that
being wanted, the solution ended up being __proto__ assignment),  
String.create,
Number.create, Boolean.create, RegExp.create and ... whatever [[Class]]
values I'm forgetting.

Prototype inheritance only inherits properties, so the non-property  
behavior
of an object must live on the top object. Inheriting from an Array won't  
make
you an array, so you need a way to make an Array inherit from something  
else
to make your own extended Arrays, or Dates.

>> I'm curious to know if there are reasons I've missed why  
>> Proxy.createFunction() doesn't support a custom prototype. It seems to  
>> me like a nice additional expressiveness without any great loss of  
>> language invariants. But I may have missed something.
> With your solution, by removing Function.prototype from the chain, proxy
> functions couldn't be .call()-ed or .apply()-ed

Well, you could do: Function.prototype.call.call(funcProxy, null, arg1,  
arg2)
if you want to be absolutely certain.

/L
-- 
Lasse Reichstein - reichsteinatwork at gmail.com


More information about the es-discuss mailing list