Updated State of the Lambda

Brian Goetz brian.goetz at oracle.com
Tue Oct 19 09:46:23 PDT 2010


On Oct 19, 2010, at 12:02 AM, Gernot Neppert wrote:

> 2010/10/18 Reinier Zwitserloot <reinier at zwitserloot.com>:
>> Entirely separate from the discussion around implementation details, having
>> practices. I'm speaking specifically of using "this" as an object reference,
>> and not the "this.x" syntax to clarify which field / method you're referring
>> to. Those are scoped in reverse (If the SAM type has a field named "foo" and
>> the outer also does, then an unqualified "foo" reference will refer to the
>> SAM type's). Therefore, using Outer.this syntax will not be necessary; its
>> only for clarification: "x" refers to lambda's x, and "this.x" refers to
>> outer's X. You'd only need it when writing a lambda that is itself in an
>> inner class.
>> 
> 
> Hmm, but here it gets messy, doesn't it?
> One argument in favour of 'this referring to the enclosing instance'
> is that lambdas should deliberately not resemble inner classes because
> they should stand out as a new concept (at least in Java).
> 
> Unfortunately, though, lambdas *are* still instances of classes, and
> simply trying to hide that fact causes inconsistencies that should be
> at least be addressed.

No.  Lambdas are not instances of classes.  Lambdas are *converted to* SAM types.  The SAM types are instances of classes, but are really just "boxes" for the method handle (not unlike the primitive wrapper classes.)  

(In the method reference #doSomething, where #doSomething is assigned to a Runnable, does that mean that the method doSomething() is an instance of Runnable?  Surely not.)  

> Consider the following TimerTask that will cancel itself conditionally:
> 
> class MyClass
> {
>    private final void Timer timer = new Timer();
>    public void cancel()
>    {
>      timer.cancel();
>    }
> 
>    public void scheduleHelloWorld()
>    {
>       timer.scheduler( #{
>                                   System.out.println("Hello world");
>                                   if(new Random().nextBoolean()) cancel();
>                                   } , 1000, 1000 );
>    }
> }
> 
> Merely prefixing 'cancel' with 'this' will now cause the TimerTask to
> cancel the entire timer instead:
> 
> 
>    public void scheduleHelloWorld()
>    {
>       timer.scheduler( #{
>                                   System.out.println("Hello world");
>                                   if(new Random().nextBoolean())
> this.cancel();
>                                   } , 1000, 1000 );
>    }
> 
> 
> Basically the meaning of 'prefixing a variable with this' has been
> reversed compared to the 'normal case' of inner classes.
> Quite counterintuitive, I think!
> 


OK, but you really had to jump through some hoops to construct this example.  Yes, people can and will make mistakes.  (People very frequently make mistakes calling toString() or hashCode() inside of inner classes and are surprised to find what happens!)  We believe people will (a) make fewer mistakes with the lexical scoping of this, and (b) lexical scoping enables other advantages in the compiler and VM, including better type inference and performance.  




More information about the lambda-dev mailing list