Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does variable initialization of to an assignment expression [String x = (x = y)] compile?

Tags:

How does this compiles without error? As my understanding, the compiler checks the type of the variable (in this case String), then sees if the type of the expression on the right side corresponds to the variable's type (or at least a subtype but let's stick to the simple case with the String class since it's final).

public class InitClass {
  public static void main(String[] args) {
    String str = (str = "hello");
    System.out.println(str);
  }
}

My question is how does str = "hello" compile? Is the compiler already aware that str should be of type String?

like image 450
user2336315 Avatar asked Jun 14 '15 12:06

user2336315


2 Answers

When evaluating an assignment expression

First, the left-hand operand is evaluated to produce a variable. If this evaluation completes abruptly, then the assignment expression completes abruptly for the same reason; the right-hand operand is not evaluated and no assignment occurs.

That produces the variable str. Then

Otherwise, the right-hand operand is evaluated. If this evaluation completes abruptly, then the assignment expression completes abruptly for the same reason and no assignment occurs.

In your example, the right hand operand is itself another assignment expression. So str, the right hand operand of the assignment operator, is again evaluated to produce a variable, str. Then

Otherwise, the value of the right-hand operand is converted to the type of the left-hand variable, is subjected to value set conversion (§5.1.13) to the appropriate standard value set (not an extended-exponent value set), and the result of the conversion is stored into the variable.

So "hello" is stored into str. And since

At run time, the result of the assignment expression is the value of the variable after the assignment has occurred. The result of an assignment expression is not itself a variable.

the result of the assignment of "hello" to str is the value "hello", that value is again stored in str.

like image 56
Sotirios Delimanolis Avatar answered Oct 11 '22 22:10

Sotirios Delimanolis


Your case is equivalent to

String str;
str = (str = "hello");

Although the assignments are funny looking, there's nothing wrong conceptually.

Nevertheless, a variable initialization that references itself is obviously not a good idea. The compiler will try to flag it in situations that's very likely a programer error; the compiler fails to do so some times; and may also go overboard some other times.

A local variable has a stricter requirement (than a field variable) - it must be assigned first before its value is used. For example, this won't compile, because the local var is read before it's assigned.

String str;  // local variable
str = str;   // error, try to read `str` before it's assigned

A field variable always has a default initial value; nevertheless, the compiler checks for apparent programer mistakes

int x = x+1;  // error. x is field variable.

But it's not catastrophic if such checking fails, since x has a value 0 before explicit assignment

int x;
{ x=x+1; } // ok. x==0, then x==1 after assignment

However, if x is final, the code above fails, because compiler requires definite assignment of x first before reading x, the same requirement for a local variable. But this checking can be circumvented, because it's impossible to analyze and prevent it fully for field variables

final int x = (this).x+1;  // compiles!

In some cases, the compiler goes overboard, preventing legit use cases involving lambda

Runnable r1 = ()->System.out.println(r1);  // r1 is a field variable 

There's nothing conceptually problematic in this use case; it can be circumvented by (this). too.

like image 36
ZhongYu Avatar answered Oct 11 '22 22:10

ZhongYu