What is the meaning of this?

Joshua Bloch jjb at google.com
Thu Jan 28 11:19:05 PST 2010


While the initial draft spec form lambdas is a bit rough around the edges, I
believe it's a lovely piece of work. It strikes the right balance between
power, ease of use, and complexity. Thanks, Alex!

Various people have suggested that the proposed treatment of "this" in
lambda expressions is questionable. On the contrary, I believe that Alex got
it exactly right. Everywhere you write an instance method in Java (in outer
class declarations, in nested class declarations, and in anonymous class
instance creation expressions), this refers to the object on which the
method is declared. Lambda expressions should be no different.

The only serious objection I've seen raised concerns type inference: the
type of a lambda expression is inferred from the types of its return
value(s). If the return value(s) refer to this, you have a circular
dependency. But there are several ways to deal with it.

For starters, you could simply ban the use of this in returned expressions.
This approach is similar in spirit to the ban on the use of static fields in
enum constructors (JLS 8.9). While this approach isn't ideal, it's workable.
Consider this code example code, from Alex's first draft:

 #int(int) factorial =  #(int i)(i == 0 ? 1 : i * this.(i - 1));

If we came to the conclusion that we had no choice but to ban the use of
"this" in returned expressions, you could still get a similar effect, albeit
a bit more verbose:

 #int(int) factorial =
   #(int i)(if (i == 0) return 1; else {int j = this.(i - 1); return i *
j;};

And I'm not convinced that we have to go that far. This problem is all about
type inference, and a common approach to type inference is to let the
compiler do the best it can, and help it if necessary. Java already does
this today, e.g., in the inference of type parameters in generic method
invocations. So, for example, perhaps the following could be legal:

  #int(int) factorial =  #(int i)(i == 0 ? 1 : i * (int) (this.(i - 1)));

In the above lambda expression, the return value (i == 0 ? 1 : i * (int)
this.(i - 1)) does mention this, but not in a way that affects its type. Its
type is int, regardless of the type of this. Would this approach work? I
don't know. The compiler can't know if the cast of (this.(i - 1)) to int is
legal until it's finished examining all of the returns in the lambda
expression (in this case, there's only one). But it suggests that there may
be hope for allowing limited use of this in returned expressions. A bit of
cleverness may go a long way here.

Entirely banning the use of this in lambada expressions is a very bad idea.
It amounts to throwing out the baby with the bath water. If you need to get
your hands on the function object created by a lambda expression, but
this doesn't
provide it, you're out of luck.There is no general-purpose workaround. And
people will be tempted to use workarounds that aren't thread-safe, such as
stashing the lambda in a field.

Evaluating this as if it were used in the context enclosing the lambda
expression is a gratuitous inconsistency that violates the principle of
least astonishment. Moreover, it's strictly less powerful than evaluating this
in the context of the implicit method declaration: you can always get
a reference to an enclosing object using a qualified this.

            Josh


More information about the lambda-dev mailing list