block lambda revival, now with semantics
Brendan Eich
brendan at mozilla.com
Mon May 23 06:57:15 PDT 2011
On May 22, 2011, at 10:15 PM, Kam Kasravi wrote:
> Is this valid?
>
> function Person(a) {
> this.age = a;
> }
> Person.prototype.myage = {|| this.age};
Block-lambda, per Tennent's Correspondence Principle as cited, uses the same this as if you moved the code inside the {|| ... } outside. This is so expr is equivalent to {|| expr }(). JS hackers do not see function () { ... } so should not expect this to change meaning.
(For this reason among others, block-lambdas have no [[Construct]] internal method. Same as for built-in functions in ES1-5.)
So this is not going to do what you want below:
> function info(myage) {
> console.log('my age is '+myage());
> }
> info(new Person(10).myage);
> info(new Person(12).myage);
Enclosing the block-lambda within the constructor works:
function Person(a) {
this.age = a;
this.myage = {|| this.age};
}
Note that in this case, unlike the case with a function expression instead of the block-lambda, the implementation can optimize aggressively: no other this can be bound dynamically in any subsequent call via new Person(10).myage() or myage() in info. This is a stronger guarantee than if Person used
this.myage = function () { return this.age; }.bind(this);
in the absence of aggressive static analysis (without which, who knows what bind means at compile time)?
The full closure pattern works too, of course:
function Person(a) {
return {get age() { return a; }, myage: {|| a}};
}
but you have to commit to accessors.
One last note: freezing and joining (see # usage in http://wiki.ecmascript.org/doku.php?id=strawman:arrow_function_syntax referencing http://wiki.ecmascript.org/doku.php?id=strawman:const_functions) do not enable much more optimization in this constructor pattern, however you do it. Whether closing over this or the parameter a, the joined block-lambda (or function) identity cannot join across the Person closure boundary.
(I did not make block-lambdas implicitly frozen and joined since some on TC39 and in the community object to that kind of change without opt-in syntax, and because it doesn't help much, given the change to make this a lexical "upvar".)
So block-lambdas are not going to solve the "bound method" cost problem in JS. For that, you need a class proposal that automatically binds methods to the receiver while at the same time disallowing any kind of dynamic inheritance. ES4 after ActionScript 3 had this; Java etc. do too of course.
Does JS really need it, vs. the prototypal function-valued properties as methods pattern? In any event, nothing block-lambdas or any other this-capturing form can fix by themselves.
/be
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.mozilla.org/pipermail/es-discuss/attachments/20110523/429d9bad/attachment.html>
More information about the es-discuss
mailing list