Why isn't a final variable always a constant expression?
Asked Answered
M

3

45

In the below code:

final int a;
a=2;
byte b=a;   // error: possible loss of precision

Why do I get this error? Isn't a final variable compile time constant expression and hence implicitly narrowed to byte during the assignment?

In other words isn't the above code equivalent to:

final int a=2;
byte b=a;
Mckinnon answered 11/6, 2015 at 15:33 Comment(0)
B
43

The compiler isn't that smart.

We can tell that the value will always be 2. But what if we had something like this?

class ABC{
    final int a;

    public ABC(){
       if(Math.random() < .5){
          a = 2;
       }
       else{
          a = 12345;
       }

       byte b = a;
    }
}

The compiler is not smart enough to tell these two cases apart, so it gives you an error instead.

Boutwell answered 11/6, 2015 at 15:43 Comment(5)
In fact the compiler isn't allowed to be that smart.Misconstrue
@Misconstrue That's some serious primitive religion there. Seriously: Why is that? Compilers are sensitive to numbers 1, 2, 4, and etc when multiplying. The case in this answer is clearly unsolvable, because the values returned from random depends on the time the program starts.Tokharian
@Tokharian But even if the computation were deterministic and the compiler could figure it out, it still would not be allowed to treat it as a constant expression (removing the need for the cast). It's important that what is or isn't a valid java program doesn't depend on how smart a particular compiler is.Ori
@Ori You are just saying that compilers should stick to the standard. Good point.Tokharian
@Tokharian Pretty much. In C++ it's common for compilers to add their own extensions. In Java, it's basically forbidden (see the Microsoft lawsuit).Dahl
I
51

From the JLS

A blank final is a final variable whose declaration lacks an initializer.

A constant variable is a final variable of primitive type or type String that is initialized with a constant expression (§15.28).

Your variable

final int a;

is a blank final variable. It lacks an initializer. The second paragraph doesn't apply to it because it is not initialized at declaration. It therefore isn't a constant expression.

This applies to fields as well.

Iscariot answered 11/6, 2015 at 15:37 Comment(0)
B
43

The compiler isn't that smart.

We can tell that the value will always be 2. But what if we had something like this?

class ABC{
    final int a;

    public ABC(){
       if(Math.random() < .5){
          a = 2;
       }
       else{
          a = 12345;
       }

       byte b = a;
    }
}

The compiler is not smart enough to tell these two cases apart, so it gives you an error instead.

Boutwell answered 11/6, 2015 at 15:43 Comment(5)
In fact the compiler isn't allowed to be that smart.Misconstrue
@Misconstrue That's some serious primitive religion there. Seriously: Why is that? Compilers are sensitive to numbers 1, 2, 4, and etc when multiplying. The case in this answer is clearly unsolvable, because the values returned from random depends on the time the program starts.Tokharian
@Tokharian But even if the computation were deterministic and the compiler could figure it out, it still would not be allowed to treat it as a constant expression (removing the need for the cast). It's important that what is or isn't a valid java program doesn't depend on how smart a particular compiler is.Ori
@Ori You are just saying that compilers should stick to the standard. Good point.Tokharian
@Tokharian Pretty much. In C++ it's common for compilers to add their own extensions. In Java, it's basically forbidden (see the Microsoft lawsuit).Dahl
B
2

As final variables can be delayed initialized and the compiler cannot determine for b that it has a value in the case branch.

Baeyer answered 11/6, 2015 at 15:37 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.