Recursive lambdas

Alex Buckley Alex.Buckley at Sun.COM
Mon Feb 22 02:20:11 PST 2010


The ability for a lambda expression to reference itself during 
initialization is noted in the 0.1.5 spec draft, but not actually 
specified. However, the answer is clear: the value of a variable of 
function type is a reference. fac.(...) makes reference to the lambda 
instance resulting from evaluation of #(int x)(x<=1...). This holds 
whether fac is a local variable or an instance variable. As always, 
extravagant aliasing is best avoided.

Alex

Alex Blewitt wrote:
> It has been suggested that recursive lambdas can be defined without any assumption of 'this' as follows:
> 
> #int(int) fac = #(int x)(x <= 1 ? 1 : x * fac.(x-1));
> 
> There may be confusion in the case of 'fac' being overwritten in the remainder of the body:
> 
> #int(int) fac = #(int x)(x <= 1 ? 1 : x * fac.(x-1));
> #int(int) other = #(int x)( fac.(x) ); // Not used in this example, see below
> #int(int) old = fac;
> fac = #(int x)(0);
> old.()//
> 
> What does (should) old.() result in? In the case of a lambda-this, the answer would be clear; it would return the factorial as before. However, ther are two ways of interpreting the execution of old.() here:
> 
> * The embedded 'fac' retains its old reference from when it was defined
> * The embedded 'fac' is interpreted in the current scope, and so returns 0
> 
> This is a contrived example, but now let's hoist these to member variables of a class:
> 
> class Foo {
>   #int(int) fac = #(int x)(x <= 1 ? 1 : x * fac.(x-1));
>   #int(int) other = #(int x)( fac.(x) );
>   Foo() {
>     #int(int) old = fac;
>     fac = #(int x)(0);
>     old.(); // What does this return?
>   }
> }
> 
> One might argue that it's the same result. But in this case, 'fac' can refer to one of two things:
> 
> * The lambda-this
> * The reference to this.fac as a field in the class
> 
> Under the first interpretation, the effect is the same as before - it prints the factorial correctly. However, under the second interpretation, it will print 0.
> 
> The 'other' here demonstrates the problem. We have two lambdas, both with recursive calls to fac.(x) in them; however, the 'other' will always refer to the field 'fac' in the enclosing scope by reference rather than by value (will it?) Mark's example yesterday suggests that it might:
> 
> class Foo {             
> 	Runnable r = new Runnable() {
> 		public void run() {
> 			r.run(); // refers to Foo.this.r, and so will see changes to r
> 		}
> 	};
> }
> 
> One can special-case this (or treat it as an oddity that no-one will worry about) but I thought I'd bring it up in the result of Mark's post.
> 
> Alex
> 


More information about the lambda-dev mailing list