On 11.10.2010 20:07, Tom Van Cutsem wrote:

    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.

Yeah, the same as in ruby with its /method_missing/ -- there also public API of an object is a set of accessor methods (and there are only methods) and instance variables are not available from the outside without having an accessor.

In Javascript, there is only property access, no true method invocation. Thus, there can be only missing properties, not missing methods.


Yeah, I know.

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

Yes, I know and understand it. Though, was asking about possible solution (with analyzing a call-site context).


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,

No, it does allow. It exactly analyzing the context of a call-site (whether it is a simple property reading or besides the reading the property there is also a call expression). I can simply add /__noSuchMethod__/ to my implementation and the method will automatically be called (btw, have just added, you may test it). First of course will be called the /get/ method of the handler with property name /__noSuchMethod__/ and if an object has such a function, it will be called with needed method name and needed arguments.

As I said, I can even implement it (again -- without a big practical need, but just 'cause of academic curiosity) without native SpiderMonkey's /__noSuchMethod__/ (e.g. naming it /methodMissing/) -- all is needed is to catch /TypeError/ with a message /"not a function"/ which will provide needed reference's components (a base and a property name to call); unfortunately, it's harder with arguments.

So /__noSuchMethod__/ does catch this case. And exactly in the right way -- it handles /non-existing property/ and only if there is a call expression in the call-site. On the other hand (and again correctly) -- it does /not/ handle /existing properties which are not functions /(you again may check in the updated script, I've added tests).
/
//
/
/ /so I don't think the strawman implementation is "wrong" in this regard.

It's wrong because it's always returns a function. Which means with such a proxy (which is a prototype of a proxied object) -- all you can is just call these functions. Regarding current implementation on the strawman proxies page: first, the invariant === is broken (since always a new function is returned). But this is not so essential, as I mentioned, theoretically it may satisfy === invariant, returning each time the same function (with saving a newly created function in some dispatching table), but practically it's unsoundly complicated and inconvenient. Second, that is more essential, repeat -- with such an implementation, all we can is just to call these our function, which brings us to broken case if e.g. /foo.toString()/ is called, which should be found in e.g. /Object.prototype/.

Of course this case can be managed (for example, to check first, whether the /name in object/: if not -- return our wrapper function, if it is -- return object.toString). However, with such object we can't manage /being outside/ (i.e. neither in /createHandled/ scope, nor in the proxy handler) the case of dynamic conditional property definition: i.e.

if (!("foo" in object)) {
  // ad-hoc implementation of object.foo
}

But it will never be undefined, since it's always defined and is a new function which call hoSuchMethod trap.

With the current __noSuchMethod__, non-existent properties will show up as "undefined" values when queried via property access.

As I mentioned, current __noSuchMethod__ of SpiderMonkey works as needed and expected.

In contrast, the strawman implementation would return a function.

Yes, and there are exact issues with it which I also mentioned above.

Neither is satisfactory if the user expects a non-function value.

Well, yeah. But the case with if (!foo.bar) foo.bar = {...} is here for years, and with this implementation it's broken.

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).

Yes, indeed and exactly.

As it stands, the Proxy API does not support this use case.

Well, so much the worse for Proxy API.

    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.

Oh, I wasn't aware about the proposal with the ad-hoc/parametrized get. Why didn't you say from the beginning? It's completely enough if we can distinguish a call-site context (i.e. simple property read or with a followed call expression). But from this viewpoint, it just the alias for the noSuchMethod. It's better to have it separated from the parametrized get.

get: function (rcvr, name, isCall) {
  // handle reading with call expression
  if (isCall) {
    // btw, where are arguments of a call? another parameter?
  }
  // handle simple reading
}

or

get: function (rcvr, name) {...}
noSuchMethod: function (name, args) {...}

Since we did not make progress on that feature, I'm afraid a dedicated 'noSuchMethod' hook will not fundamentally change things.


Where this proposal is described? I didn't see it. I'll support it. Even if the committee won't agree on noSuchMethod, it'd at least will be great to have a parametrized get. Though, repeat, IMO, a separated method for this case is better.

Dmitry.

Cheers,
Tom

_______________________________________________
es-discuss mailing list
[email protected]
https://mail.mozilla.org/listinfo/es-discuss

Reply via email to