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