Recursive lambdas
Alex Blewitt
alex.blewitt at gmail.com
Mon Feb 22 02:42:29 PST 2010
On 22 Feb 2010, at 10:20, Alex Buckley wrote:
> 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.
That would make sense (and avoid hairy problems) but note that we now have .fac() referred to in potentially two different ways here:
> class Foo {
> #int(int) fac = #(int x)(x <= 1 ? 1 : x * fac.(x-1));
> #int(int) other = #(int x)( fac.(x) );
> }
In the definition of 'other', how is 'fac' captured? If it's by reference to the instance variable, then it's possible that changes to fac could be observed by other. If it's by reference to the value of fac at the point of capture, then it's by (current) value of fac at the time.
Note that 'effectively final' doesn't help here; even if no other code in Foo mutates fac, that doesn't prevent external code from mutating fac. If fac were defined as final, then the problem goes away; but I can see this pattern being used functionally in Java code:
class Op {
#bool(Object) filter = #(Object o) { return true };
#Object[](Object[]) subset = #(Object[] o) { r = new Object[o.length]; for(int i=0;i<o.length;i++) if( /* this. */ filter ) r[o] = i[o]; return r; };
}
One could then change the definition of 'filter' to affect the operation of 'subset'.
Alex
More information about the lambda-dev
mailing list