Why does a Java Compiler not produce an unreachable statement error for an unreachable then statement?
Asked Answered
H

5

59

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?

Housework answered 24/12, 2015 at 13:30 Comment(7)
I don't understand your edit: it is an infinite loop regardless of the condition used in the if...Vaduz
@Vaduz I don't think simply addressing the if is a sufficient answer here, or it'd be a duplicate. The trick is that the if backdoor makes the compiler consider the break reachable, which unrolls to provide an exit condition.Patella
@chrylis yes I understand that - what I meant in my comment is that continue is not going to exit anything...Vaduz
@JarrodRoberson I specifically do not think this is a duplicate because this question involves an interaction that, while dependent on the special case, requires further analysis.Patella
@Vaduz I added that because the JLS description says A break, continue, return, or throw statement cannot complete normally.. Even with return it produces an error.Housework
@Vaduz Right, and the compiler is realizing that even if continue is reachable, there's no exit path from the loop.Patella
The code is unreachable, but it's not Java-unreachable.Lerner
V
56

The behaviour is defined in the JLS description of unreachable statements:

The then-statement is reachable iff the if-then statement is reachable.

So the compiler determines that the then-statement (break;) is reachable, regardless of the condition in the if.

And a bit further, emphasis mine:

A basic for statement can complete normally iff at least one of the following is true:

  • The for statement is reachable, there is a condition expression, and the condition expression is not a constant expression (§15.28) with value true.
  • There is a reachable break statement that exits the for statement.

So the for can complete normally because the then-statement contains a break. As you noticed, it would not work if you replaced break with return.


The rationale is explained towards the end of the section. In substance, if has a special treatment to allow constructs such as:

if(DEBUG) { ... }

where DEBUG may be a compile time constant.

Vaduz answered 24/12, 2015 at 13:38 Comment(7)
In that description, there is a line which says that the error will be produced if: A break, continue, return, or throw statement cannot complete normally. . Well, its fine with continue and return. But not break. :/Housework
@PriydarshiSingh that is unrelated.Vaduz
Nice analysis on the "completes normally" part.Patella
@black "iff" is a common abbreviation in mathematics for "if and only if".Josettejosey
@Josettejosey I wouldn't expect it in a formal context though, whether it's ISO (as for C++) or not.Cartie
The "unreachable code" problem is uncomputable in the general case, as it's a transformation on the general case. What can be done, however, are solutions based on certain classes of unreachable code, for which many assumptions are made, as you can see below.Presignify
@black Why not? It's an English word...Janel
P
11

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 your break as reachable because of that.

Patella answered 24/12, 2015 at 13:40 Comment(0)
M
7

From the JLS

An if-then statement can complete normally if at least one of the following is true:

> The if-then statement is reachable and the condition expression is not a constant expression whose value is true.

> The then-statement can complete normally.

So if(false) is allowed.

This ability to "conditionally compile" has a significant impact on, and relationship to, binary compatibility. If a set of classes that use such a "flag" variable are compiled and conditional code is omitted, it does not suffice later to distribute just a new version of the class or interface that contains the definition of the flag. A change to the value of a flag is, therefore, not binary compatible with pre-existing binaries . (There are other reasons for such incompatibility as well, such as the use of constants in case labels in switch statements;)

Mopes answered 24/12, 2015 at 13:40 Comment(0)
D
4

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) via if.

Disputable answered 24/12, 2015 at 16:23 Comment(0)
P
1

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 print true for every int x (source).

    System.out.println((x + x & 1) == 0);
    System.out.println((x + -x & 1) == 0);
    System.out.println((-x & 1) == (x & 1));
    System.out.println(((-x ^ x) & 1) == 0);
    System.out.println((x * 0x80 & 0x56) == 0);
    System.out.println((x << 1 ^ 0x1765) != 0);

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

Peremptory answered 30/12, 2015 at 9:21 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.