Improving ECMAScript as a compilation target
Brendan Eich
brendan at mozilla.com
Tue May 5 00:09:46 PDT 2009
On May 4, 2009, at 10:46 PM, Allen Wirfs-Brock wrote:
>> -----Original Message-----
>> From: Brendan Eich [mailto:brendan at mozilla.com]
>>
>> On May 4, 2009, at 6:20 PM, Allen Wirfs-Brock wrote:
>>
>>> In the function defined for the example's invoke item the first
>>> argument to apply probably should be obj rather than peer.
>>
>> Possibly, but in the example peer[id] may be a function that insists
>> on |this| being bound to peer, not obj. If the function is pure, the
>> arguments flow in and a result comes back, and the catchall delegates
>> without mutating peer or obj. If the function mutates |this|, then
>> the
>> effects can be recovered by calling other methods, or by property
>> access, which again is delegated without a wrapper.
>
> You're right it is probably situational. As I look at the example
> again, I'm uncertain about your intent for the invoke and construct
> properties of the catch all descriptor. My original assumption was
> that they would be invoked if obj (the object itself, not one of its
> properties) was invoked or new'ed. However, in that case there
> wouldn't be a property id to pass as an argument to the handler
> function, yet the function signatures for invoke and construct in
> the example have an id argument.
Yes, they are for "invoking a method" and "constructing via new
applied to a method" respectively. From
http://wiki.ecmascript.org/doku.php?id=discussion:catchalls
"One user expectation, fed and watered by E4X, is that methods are not
properties, or to avoid this JS oxymoron, that methods are not in the
default property namespace:
js> x = <room><width>12</width><length>16</length></room>
<room>
<width>12</width>
<length>16</length>
</room>
js> x.length
16
js> x.length()
1
Another point in favor of a call * catchall is efficiency:
var o = {
peer: ...,
get *(id) {
return function () { return this.peer[id](this.peer, arguments) }
}
}
creates a closure per get, whether or not the get result is called.
Whereas
var o = {
peer: ...,
call *(id, args) { return this.peer[id].apply(this.peer, args) }
}
creates a generic call forwarder."
It isn't just E4X. People want to make objects with arbitrary methods
callable on a given object, e.g. when bridging to CORBA or Java or
whatever. There may be static types in the peer space, but still you
don't want to mandate a custom JS object mapping exactly the M methods
in type T via hardcoded proxying. You don't want to reify the methods
as function objects stored in obj, even. You want to direct the call
through to the peer function.
This is why invoke has an ident leading parameter in http://wiki.ecmascript.org/doku.php?id=proposals:catchalls
.
Invoking a callable object is best done through a separate protocol,
not catchalls but something like the ES4 intrinsic::invoke (contrast
to meta::invoke the catchall hook for invoking a property, originally
not expressed by that qualified name but rather via dedicated 'call
*(id, args) {...}' syntax in the property initialiser production under
the object initialiser syntax).
> The other possibility, at least for invoke, is that the handler is
> invoked whenever an attempt is made to call the value of an non-
> existent property of obj.
The general intention for catchalls is to call the action hook only
when the property is missing. The odd case is set, vs. add in the
strawman (or first-set vs. every-set in the prose).
There's a less common case of wanting every-get too, to filter results
of and/or control access to existing properties.
> In other words invoke and get are mutually exclusive. I'm guessing
> that wasn't you intent as it really doesn't match the ES meta-model.
No, you've got it -- get and invoke are exclusive precisely to avoid
cons'ing up methods -- function-valued properties -- just to dispatch
calls.
> However, I think I was momentarily thinking that way when I made
> the observation about passing obj rather than peer. That raises for
> me some usability concerns. I'm well aware that a "method" is called
> by first getting the property value and then invoking the function
> value returned from the get but I still made the mental slip of
> thinking that invoke in the catch all descriptor was about calling a
> method of obj rather than calling obj itself. I expect that the
> typical non-expert JavaSript programmer will be even more prone to
> making that mistake.
This is the non-mistake droid you are looking for, and what I was
trying to sketch. I'll clarify the strawman page. Thanks for bringing
this to light.
>>> I would be inclined to specify an additional argument (probably the
>>> first) for each handler function that would be passed the "this"
>>> value. Closure capture like is done in the example works but my
>>> intuition is that there will be situations where it would be handy
>>> to use the same catch-all descriptor for several objects.
>>
>> Agreed, but why not use |this| instead of an extra (leading)
>> parameter?
>>
>
> Good point, it depend upon whether the model is that the entire
> descriptor is associated with obj as its catch all handler or
> whether the individual handler functions are separately associated
> with obj. If the entire catch all descriptor object is associated
> with obj then I would expect that when one of its methods is invoked
> that the this object would be the descriptor object rather than
> obj. On the other hand, if the descriptor object is just a way to
> aggregate a bunch of optional arguments to defineCatchAll (similar
> to the defineProperty pattern) then it is reasonable to assume that
> the individual handler functions are invoked as if they were methods
> of obj and thus the this value would be obj.
That's the idea -- like defineProperty, the object initialiser syntax
is a convenient approximation of named parameter passing. No this-
binding implied (as indeed none is implied in other object
initialisers).
/be
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.mozilla.org/pipermail/es-discuss/attachments/20090505/e83c2bca/attachment-0001.html>
More information about the es-discuss
mailing list