3
class Test {
  int a;

  void method() {
    a = 1;
    int a = a = 2;
    a = 3;
  }
}

There are lots of as in method. What are they all referring to?

Raedwald
  • 46,613
  • 43
  • 151
  • 237
Andy Turner
  • 137,514
  • 11
  • 162
  • 243

1 Answers1

5

This is a simple example of the bizarreness of Java's scoping rules.

a = 1;
int a = a = 2;
a = 3;

Breaking it down line-by-line:

  • a = 1; is referring to the member variable.
  • a = 3; is referring to the local variable, because it's after the declaration of the local variable. It's pretty confusing that you can refer to two different symbols via the same identifier, in the same method.
  • int a = a = 2;: the second a is the local variable.

The self-reference in the variable declaration is really curious. You can find this in the language spec:

  • The scope of a local variable declaration in a block (§14.4) is the rest of the block in which the declaration appears, starting with its own initializer and including any further declarators to the right in the local variable declaration statement.

It is also true that member variables can refer to themselves in their own initializer; but this is for a slightly different reason:

  • The scope of a declaration of a member m declared in or inherited by a class type C (§8.1.6) is the entire body of C, including any nested type declarations.

I have yet to find a compelling reason for the existence of this rule for local variables; maybe you just really really want to make sure it's assigned. The only thing that I can think it allows you to do is to use the variable as temporary storage in the evaluation of the initializer, for example:

int a = method(a = somethingThatIsReallyExpensiveToCompute(), a);

would be equivalent to:

int a;
{
  int tmp = somethingThatIsReallyExpensiveToCompute();
  a = method(tmp, tmp);
}

Personally, I'd rather see the second form of the code, as the evaluation of the first just seems obscure.

Andy Turner
  • 137,514
  • 11
  • 162
  • 243
  • 1
    When they excluded the variable’s initializer from its scope, `int a = a;` was a valid statement, i.e. when there is another `a` in the outer scope, like in your example. Now if that’s not obscure… – Holger Sep 21 '18 at 08:49
  • @Holger interesting point. Purely navel-gazing, of course, but I wonder if it would have been possible to make *neither* in scope there, and just avoid both kinds of obscurity...! – Andy Turner Sep 21 '18 at 10:51
  • Notwithstanding the java specification excerpts above, with the left-to-right rule and precedence rules alone, `int a = a = 2;` can be broken down into: `int a = (a = 2);`, then `int a; a = 2; a = a;` – Mark Jeronimus May 01 '19 at 08:49