If I try to compile
for(;;)
{
}
System.out.println("End");
The Java compiler produces an error saying Unreachable statement
. But if I add another "unreachable"(according to me) break
statement and make it:
for(;;)
{
if(false) break;
}
System.out.println("End");
It compiles. Why does it not produce an error?
From the JLS
So
if(false)
is allowed.Basically, unreachable code is detected by analyzing the program statically without actually running the code. While the condition will be checked at runtime. So, when this analysis takes place it does not actually look in to the condition but just check that
break;
is accessible(reachable) viaif
.The behaviour is defined in the JLS description of unreachable statements:
So the compiler determines that the then-statement (
break;
) is reachable, regardless of the condition in theif
.And a bit further, emphasis mine:
So the for can complete normally because the then-statement contains a
break
. As you noticed, it would not work if you replacedbreak
withreturn
.The rationale is explained towards the end of the section. In substance,
if
has a special treatment to allow constructs such as:where DEBUG may be a compile time constant.
The core reason Java doesn't detect all unreachable statements is that it's generally impossible to answer whether the code is reachable or not. This follows from the fact that halting problem is undecidable over Turing machines.
So, it's clear that all unreachable statements cannot be detected, but why not to try evaluating conditions? Imagine now that the condition used is not just
false
but something like~x == x
. For example, all these statements will printtrue
for everyint x
(source).The statements can be rather complicated; it takes time to resolve them. It would significantly increase build time, and after all, it will not detect all unreachable statements. Compiler was designed to take some efforts but not spend too much time for that.
The only question remained is: where to stop resolving conditions? The reasons for that don't seem to have mathematical justification and are based on usage scenario. Rationale for your particular case is given by JLS-14.21
As explained in my answer to a similar question, the specific construct
if(compile-time-false)
is exempt from the unreachability rules as an explicit backdoor. In this case, the compiler treats yourbreak
as reachable because of that.