Proxies: get+fn vs. invoke

Tom Van Cutsem tomvc.be at gmail.com
Mon Oct 11 09:07:06 PDT 2010


>
> The most interesting question for me is mentioned several times (the last
> one was by Brendan in his slides from the lates JS Conf) "get + defining Fn"
> vs. invoke trap.
>
>
> Yes, there are some cons: a non-existing method can be extracted as a
> funarg for later use. It also do not break invariant with call/apply methods
> applied for the method:
>
> var foo = proxy.nonExistingMethod;
>
> Thus, *foo* is a real function and also *proxy.nonExistingMethod()* is the
> same as *proxy.nonExistingMethod.call(undefined)*.
>
> However, I don't see how can I implement a generic *get* method in the
> proxy handler? I.e. I'd like to trap at the same time both: reading simple
> properties and also invocation of methods. In my script these are: *
> __get__* (traps reading of all properties), *__noSuchProperty__* (traps
> reading only of missing properties) and *__noSuchMethod__* (traps methods
> invocations).
>

Ok, so all of this is inspired by Smalltalk's "doesNotUnderstand:" trap, and
derivatives, right?

The thing is: in Smalltalk, there is no property access, only message
sending (method invocation). Thus, there can be only missing methods, not
missing properties.
In Javascript, there is only property access, no true method invocation.
Thus, there can be only missing properties, not missing methods.

So I think the simple answer is: you can't have both. In Javascript,
__noSuchProperty__ trumps __noSuchMethod__

It would be analogous to asking for a "doesNotUnderstandProperty" trap in
Smalltalk: such a trap would never get triggered, since "obj foo" is a
message send in ST, not a property access.


> Yes, everything correct with stratification of the meta- and normal-
> levels; I know that this is the main reason. As I said (and repeat it again)
> -- my implementation with __Ugly?PythonsNames__ is just an academic
> curiosity -- to play with proxies.
>

Sorry, I didn't know what your intentions were. Academic curiosity is good
;-)


> And was playing with them, I backed to the ideological dilemma which was
> mentioned also several times: "get + fn vs. noSuchMethod/invoke". This is
> what Brendan mentioned before and also in the last slides of the recent JS
> Conf (I saw only slides, I didn't see yet video of Brendan's talk -- maybe
> he already answered this question? However, I didn't find the answer in
> slides).
>

> The main (42? ;)) question is: how having *one get* method in a proxy's
> handler to handle both cases of a call-site -- a *property reading* and a
> *method invocation* ?
>
>
> foo.bar
>
> and
>
> foo.bar()
>
> Currently I understand, that implementation of the __noSuchMethod__
> described in the strawman article is just wrong -- because *get* method of
> the handler *always* returns a *function*. That means, *foo.bar* - is a
> function, *foo.baz*, *foo.whatTheHack* - is also a function. How a user
> will differentiate accesses to a non-function properties to a function
> properties?
>

As I understand it, even spidermonkey's __noSuchMethod__ does not currently
allow one to tell the difference, so I don't think the strawman
implementation is "wrong" in this regard. With the current __noSuchMethod__,
non-existent properties will show up as "undefined" values when queried via
property access. In contrast, the strawman implementation would return a
function. Neither is satisfactory if the user expects a non-function value.

What you are asking for is a hook that returns a different value depending
on its context of use (property access vs method call syntax). As it stands,
the Proxy API does not support this use case.



> And exactly the last case can be trapped with noSuchMethod. I can even
> implement it in my script (e.g. catching onError with debugger service, or
> even simple window.onerror -- though will be hard with arguments). But it
> can be additional trap for a proxy:
>
> noSuchMethod: function (name, args) {
>   console.log(name, args);
> }
>
> then:
>
> proxy.nonExisting(1, 2, 3); // get "nonExisting" -> call-site contains call
> expression -> noSuchMethod("nonExisting", [1, 2, 3])
>
> The issues are also known:
>
> proxy.nonExisting(1, 2, 3); is not the same as
> proxy.nonExisting.apply(null, [1, 2, 3]) and we can't extract
> proxy.nonExisting as a function ('cause obviously it's not a function). But
> what is more convenient for a user -- to catch such methods or to keep
> invariants with apply/funargs? Also, as I mentioned, even if it is done via
> get, then *to keep === invariant*, get should return always the same
> missing function for a property (which means to keep some dispatch table).
> So, anyway, some invariants will be lost anyway (or will be
> complex/inconvenient in implementation) and it's needed to choose what is
> better for a user. I think it will be good to have additionally for proxies
> noSuchMethod trap.
>

I think this proposal can be reduced to the previous proposal of
parameterizing the 'get' trap with a flag that indicates context of use.
Since we did not make progress on that feature, I'm afraid a dedicated
'noSuchMethod' hook will not fundamentally change things.

Cheers,
Tom
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.mozilla.org/pipermail/es-discuss/attachments/20101011/006b18cd/attachment.html>


More information about the es-discuss mailing list