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