[[Invoke]] and implicit method calls

Tom Van Cutsem tomvc.be at gmail.com
Fri Sep 20 06:50:59 PDT 2013

2013/9/20 Brendan Eich <brendan at mozilla.com>

> Tom Van Cutsem <mailto:tomvc.be at gmail.com>
>> And finally, if all we gain by leaving out invoke() is a simpler API,
>> then we should probably reconsider all derived traps. As I mentioned
>> earlier, we can easily get rid of traps like has(), hasOwn(), keys() etc.,
>> and they don't seem nearly as important to intercept as method invocation.
> But this makes proxies for special purpopes strictly harder to write, even
> with a base handler implementation. Please correct me if I'm mistaken.

Yes, it's a trade-off: if we get rid of all "derived" traps (only retain
the "fundamental" ones), this makes it impossible to have inconsistencies
between traps (this is Allen's main concern), but it also means proxies
have less direct control over intercepted operations. Also, the guiding
principle that MarkM and I used was to introduce derived traps whenever
this would allow a proxy to intercept an operation with less allocations.

To make matters more concrete, consider the has() trap:

"foo" in proxy // triggers has(target, "foo"), returns a boolean

Strictly speaking, we could do without the has() trap and instead call the
getOwnPropertyDescriptor() trap, and then test whether it returns a
descriptor or undefined (+ climb the prototype if it returns undefined).
But this interface potentially requires consing a property descriptor only
for it to be tested against undefined. So the has() operation: a) allows
more direct interception of the in-operator and b) with potentially less

If you think about it, these very same arguments apply to the invoke() trap.

> So I think we are better off with get+invoke, but I'm still troubled by
> the double lookup. Any thoughts on parameterizing invoke by (id | func)?

Parameterizing invoke() by (id | func) to me is almost the same as adding a
boolean "conditional" flag: most handlers will need to branch based on the
type of the argument, because you cannot do:

invoke: function(target, idOrFunction, args, receiver) {
  return target[idOrFunction].apply(receiver, args);

Users would have to:

invoke: function(target, idOrFunction, args, receiver) {
  if (typeof idOrFunction === "string") {
    return target[idOrFunction].apply(receiver, args);
  } else {
    return idOrFunction.apply(receiver, args);

Given that ...

a) membrane proxies work fine with the get+call pattern
b) a non-membrane proxy can be made to work with the get+call pattern, if
it implements sufficient logic in its "get" trap
c) conditional method calls in the wild (i.e. outside the spec) will
continue to use the get+call pattern

... I'm inclined to advocate the status-quo: just do get+call for
conditional method calls, keep invoke() for ordinary method calls.

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.mozilla.org/pipermail/es-discuss/attachments/20130920/4c09f07d/attachment-0001.html>

More information about the es-discuss mailing list