Tech talk on proxies and traits

Mark S. Miller erights at google.com
Sat May 1 13:52:56 PDT 2010


[+stay]

On Sat, May 1, 2010 at 12:10 PM, Faisal Vali <faisalv at gmail.com> wrote:
>>[...]

> Thanks for the clarification Mark.
>
> As I read the proposal, I do wish an invoke-like trap had been
> accepted - but I understand that there were some technicalities that
> proved unresolvable.
>
> It might be useful to be able to tell when someone was accessing a
> property as a function call:
>
> str_proxy.length -vs- str_proxy.length()
> db_proxy.data -vs- db_proxy.data() -vs- db_proxy.data( { filter : '....' } )
>
> I realize that maintaining the invariant of "o.m(a) is equivalent to
> var f = o.m; f.call(o,a)" is advisable - but are we certain that it
> should be mandatory in the setting of proxies (i.e represent a true
> invariant)? In the world of proxies (or for that matter 'get'
> accessors in es5) we can't even guarantee that two sequential accesses
> of the same property will return the same value, object or function.

You are correct. This invariant is a pleasant property but not a
necessary one. Our first proxies proposal did have an invoke() trap.
Although we recognized the invariant breakage as an argument against
it, it wasn't a fatal argument. The last straw was instead the
sequencing issue Brendan raised: Now that ES5 standardizes getters, in
a method call, ES5 is clear that the getter runs before the method
arguments are evaluated. For example:

    var x = 3;
    obj = { get foo() { ++x; return function(n) { return x * n; }; }};
    obj.foo(x *= 2);  // should return 64

If the method's arguments were evaluated before the getter were run,
the answer would be 42. Although I agree that 42 is the ultimate
answer, it is not the answer sanctioned by the ES5 standard. Were the
invoke() trap to be triggered *instead* of the get() trap above, it
would only be triggered after the method arguments were evaluated, and
so 42 is the only answer it could know to emulate.

The more I have become aware of the costs of this sequencing
semantics, the more unfortunate I think it is. Mike Stay (cc'ed) is
currently repurposing the Cajita translation framework to create
approximately an ES5/strict to ES3R translator we're calling ES5/3. In
order to avoid exceeding the 20% overheads currently paid by Cajita
for normal property access and method calls, we're going to violate
this sequencing and give 42 for this example. (A bit of testing
reveals that V8 gives 42 as well. FF and Safari both correctly give
64.)


> There is convenience to being able to type either proxy.length or
> proxy.length() and have it do the right thing.

I think having "x.length()" ever be a synonym for "x.length" in JS is
a terrible idea.


> Since I do not have that much experience with interceptors, it is too
> early for me to say that preventing the 'get' handler from
> distinguishing whether a property is about to be 'called' is
> definitely a loss in expressivity.  I sense it might be useful to have
> that feature.  A simple solution that would allow maintaining the
> above mentioned 'invariant' in most cases and allow breaking it when
> necessary would involve a flag passed into the 'get' handler
> indicating that the property is about to be 'called'.  What would be
> the negative ramifications of such a solution (asides from the fact
> that it may get abused - like the 'get' accessor in es5 ;)?

Among the many alternatives we've considered, passing such a flag was
not among them. I haven't thought about it in any depth yet, but my
first reaction is positive. It may solve a number of problems that are
otherwise unpleasant; about which more later...

Thanks for the suggestion!


>
> Thanks.
>
> Faisal Vali
> Radiation Oncology
> Loyola
>



-- 
    Cheers,
    --MarkM


More information about the es-discuss mailing list