Win a copy of Cross-Platform Desktop Applications: Using Node, Electron, and NW.js this week in the JavaScript forum!
  • Post Reply Bookmark Topic Watch Topic
  • New Topic

How does the Java compiler determines unreachable statements?  RSS feed

 
Arco Brouwer
Ranch Hand
Posts: 44
2
IntelliJ IDE Java Ubuntu
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
While studying for my OCA one subject that comes back every time is unreachable statements. Java will not compile the code if there are unreachable statements. I can understand that, and it sounds very logical. So far so good.
For example I have the following code snippet:(1) and (2) do not compile because there are unreachable statements. Which I understand, because the logical check always results to false.
When I look at the code for example (3), the code is compiling, but the logical check will too always result to false since int i is always given value 0 when initializing the for loop, so i<0 will always result to false. This confuses me, because when I look at the code they all have unreachable statements in my opinion (which is obviously wrong :-) ), so they all three shouldn't compile.

My question: how does the compiler determines whether or not a statement is unreachable?
 
Carey Brown
Saloon Keeper
Posts: 2840
43
Eclipse IDE Firefox Browser Java MySQL Database VI Editor Windows
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Arco Brouwer wrote:When I look at the code for example (3), the code is compiling, but the logical check will too always result to false since int i is always given value 0 when initializing the for loop, so i<0 will always result to false.

That is NOT always false. After the first time through the loop, 'i' gets incremented to one.
 
Campbell Ritchie
Sheriff
Posts: 55351
157
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
The continuation condition sometimes only evaluates to false to the human eye; the javac tool is programmed differently.
In the first instance, line 6, it is obvious to it that the continuation condition will be false throughout; that is equivalent to
while (false)...
...which is regarded as having the body of the loop unreachable.
Line 10 is different. The loop variable is a compile‑time constant because it is marked final, so when the continuation condition is evaluated it will be false. By the way: you shou‍ld have seen a second compiler error because the increment part i++ attempts to alter the value of a final variable.
Line 14 is different again. The loop variable i is initialised, but the javac tool doesn't record its value. It is an ordinary variable, and variables change, so the javac tool forgets their value. It does not attempt to count whether there is any code after the initialisation and the continuation condition. Nor whether it is or is not re‑assigned to. So when it attempts to evaluate the continuation condition, it has no information to go on. The continuation condition become something the compiler does not handle, but leaves to the runtime.

While we are on about compiler errors, please work out why the following code won't compile:-Also work out what compiler errors you will get from this code:-The only variables where the compiler does count assignments are local variables used in a λ or local class, and then only in Java8.
 
Campbell Ritchie
Sheriff
Posts: 55351
157
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Oh, you are using j++ rather than i++; sorry for my mistake about a second compiler error.
 
Arco Brouwer
Ranch Hand
Posts: 44
2
IntelliJ IDE Java Ubuntu
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Campbell Ritchie wrote:The loop variable i is initialised, but the javac tool doesn't record its value. It is an ordinary variable, and variables change, so the javac tool forgets their value.

So if I'm not mistaken: unless a variable is a runtime constant (by making it a final variable or hardcoded booleans, javac will not use the variable value to evaluate expressions and comparissons is that right?

Campbell Ritchie wrote: please work out why the following code won't compile:-

As far as I can see the codes you mentioned will compile assuming that int i is assigned a valid integer value.
But while fiddling with your examples I encountered another case where it is 'obvious' that there is an unreachable code block:

But surprisingly enough this code snippet compiles. It also contradicts with the assumption above since there are not variables involve which javac can 'forget'. Are if/else statements completely 'ignored' by javac when it concerns unreachable statements?
 
Henry Wong
author
Sheriff
Posts: 23279
125
C++ Chrome Eclipse IDE Firefox Browser Java jQuery Linux VI Editor Windows
  • Likes 1
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Arco Brouwer wrote:
So if I'm not mistaken: unless a variable is a runtime constant (by making it a final variable or hardcoded booleans, javac will not use the variable value to evaluate expressions and comparissons is that right?


The compiler operates during compile time -- so, it needs to be a compile time constant. And compile time constants are not as simple as making the variable final... See this topic for more details... https://coderanch.com/t/454384/java/compile-time-constant

Henry
 
Henry Wong
author
Sheriff
Posts: 23279
125
C++ Chrome Eclipse IDE Firefox Browser Java jQuery Linux VI Editor Windows
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Arco Brouwer wrote:
But surprisingly enough this code snippet compiles. It also contradicts with the assumption above since there are not variables involve which javac can 'forget'. Are if/else statements completely 'ignored' by javac when it concerns unreachable statements?


If conditions operate under different rules. The Java Language Specification allows them to be unreachable, so that they can be used in the context of conditional code (such as debugging code).

Henry
 
Arco Brouwer
Ranch Hand
Posts: 44
2
IntelliJ IDE Java Ubuntu
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Henry Wong wrote:
Arco Brouwer wrote:
So if I'm not mistaken: unless a variable is a runtime constant (by making it a final variable or hardcoded booleans, javac will not use the variable value to evaluate expressions and comparissons is that right?


The compiler operates during compile time -- so, it needs to be a compile time constant. And compile time constants are not as simple as making the variable final... See this topic for more details... https://coderanch.com/t/454384/java/compile-time-constant

Henry


Thank you! That topic of you is very descriptive!
 
Arco Brouwer
Ranch Hand
Posts: 44
2
IntelliJ IDE Java Ubuntu
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Thanks for the replies. So if I take everything into account and look again at my code, I think I understand now why the following will not compile (but please correct me if I'm wrong!):

Variable i is not a compile time constant since it has not been marked as final. Therefore i<0 is not a compile time constant expression so the expression will not be evaluated during compile time.
Result is that the code will compile successfully, but the for loop will never been entered since the condition will always return false in this case.
 
Campbell Ritchie
Sheriff
Posts: 55351
157
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Arco Brouwer wrote:. . . So if I'm not mistaken: unless a variable is a runtime constant . . . javac will not use the variable value to evaluate expressions and comparissons is that right?
The javac tool keeps no record of the value of any variable other than a compile time constant.
. . . As far as I can see the codes you mentioned will compile . . .
That behaviour has obviously changed in Java8; whenever I tried it before such code wouldn't compile. That is because the value of i was forgotten and the javac tool couldn't determine that j was definitely assigned to.
. . . if (false){ . . .
There is an explanation in the Java® Language Specification about why if (false)... is permitted.
 
Arco Brouwer
Ranch Hand
Posts: 44
2
IntelliJ IDE Java Ubuntu
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Campbell Ritchie wrote:There is an explanation in the Java® Language Specification about why if (false)... is permitted.


I think the following sentence explains why the if/else statement above will compile:

JLS 14.21
An if-then-else statement can complete normally iff the then-statement can complete normally or the else-statement can complete normally.
 
Campbell Ritchie
Sheriff
Posts: 55351
157
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Arco Brouwer wrote:. . . I think the following sentence explains why the if/else statement above will compile: . . .
That wasn't what I was thinking about. Go back to the JLS link I showed you and scroll to the bottom of the page where you will see an example with if (false)... Henry has already mentioned that explanation.
 
Arco Brouwer
Ranch Hand
Posts: 44
2
IntelliJ IDE Java Ubuntu
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Yes, I have read that example.
But since Java allows the if statement to be used for "conditional compilation" purposes, doesn't that mean that when the compiler sees the mentioned if-then-else statement, the compiler will conclude that it can complete normally whatever the condition might be?
 
Stephan van Hulst
Saloon Keeper
Posts: 7719
142
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
No. Both then-statement and else-statement are reachable if the if-then-else statement is reachable, regardless of the condition. However, an if-then-else statement may not complete normally when neither the then-statement and else-statement complete normally.

 
Campbell Ritchie
Sheriff
Posts: 55351
157
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Remember that the meaning of completes normally is not the same as completes without exception. A return statement, break; etc., are regarded as completing abruptly; after abrupt completion it is not possible to write any more reachable code. So abrupt completion doesn't mean an abnormal condition; it means any following code cannot be reached by any path of execution. More details in the Java® Language Specification.
 
Arco Brouwer
Ranch Hand
Posts: 44
2
IntelliJ IDE Java Ubuntu
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
It's getting a bit complicated for a beginner, but I would like to try to understand this :-)
Assuming that an if-then-else statement can be completed normally (as stated in the previous examples), does the compiler then still looks at the conditions of the if-then-else statement to determine if code blocks within the if-then-else clause are unreachable?

P.S. Thanks for being so patient with an amateur like me :-)
 
Stephan van Hulst
Saloon Keeper
Posts: 7719
142
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
No. The JLS is very clear in this.

An if-then-else statement can complete normally iff the then-statement can complete normally or the else-statement can complete normally.

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

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

then and else statements are just normal statements. If they can be reached then whether they can be completed normally depends only on their contents.

For nested structures in general, reach works from the outside inwards, while completion works from the inside outwards. The then-statement can be reached if the if-then statement can be reached. The if-then-statement can be completed normally if the then-statement can be completed normally.

Reach is always only determined by whether an outer structure can be reached, or whether a previous structure can be completed normally.

Whether a structure can be completed normally may depend on boolean conditions, such as in the case of a while-statement. Normal completion of an if-then-statement or an if-then-else-statement NEVER depends on boolean conditions:
One might expect the if statement to be handled in the following manner:

    An if-then statement can complete normally iff 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.

  •     The then-statement is reachable iff the if-then statement is reachable and the condition expression is not a constant expression whose value is false.

        An if-then-else statement can complete normally iff the then-statement can complete normally or the else-statement can complete normally.

        The then-statement is reachable iff the if-then-else statement is reachable and the condition expression is not a constant expression whose value is false.

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

    This approach would be consistent with the treatment of other control structures. However, in order to allow the if statement to be used conveniently for "conditional compilation" purposes, the actual rules differ.
     
    Arco Brouwer
    Ranch Hand
    Posts: 44
    2
    IntelliJ IDE Java Ubuntu
    • Mark post as helpful
    • send pies
    • Quote
    • Report post to moderator
    Phew, I think I start a bit to understand the JLS, but please have mercy if I got it still wrong ;-)

    Let me conclude how I see it now:
    1. An if-then-else statement is always reachable when the if-statement can be reached. In case of a nested construction, this depends on the outer structure.
    2. Whether or not an (if-then-else) statement can be completed normally, depends on the contents of the statement, but not on the boolean condition.
    3. For while and for loops: when the condition is a constant expression which returns to false, the statement will not be reachable and this results in a compile error.
    4. Since do-while always runs at least once, the do statement itself is always reachable (regardless whether or not the statement can complete normally).
     
    Campbell Ritchie
    Sheriff
    Posts: 55351
    157
    • Mark post as helpful
    • send pies
    • Quote
    • Report post to moderator
    That sounds right; you only need to know the rules about reachability if you are sitting a cert exam; for ordinary programming you can assume that code which compiles is regarded as reachable (or is if (false) ...)
     
    Arco Brouwer
    Ranch Hand
    Posts: 44
    2
    IntelliJ IDE Java Ubuntu
    • Mark post as helpful
    • send pies
    • Quote
    • Report post to moderator
    Campbell Ritchie wrote:That sounds right;

    Took me some time to understand, but thanks for all the info provided by you, Stephan and Henry (and hopefully I forgot nobody) to understand this topic!
     
    Campbell Ritchie
    Sheriff
    Posts: 55351
    157
    • Mark post as helpful
    • send pies
    • Quote
    • Report post to moderator
    That's a pleasure
     
    Don't get me started about those stupid light bulbs.
    • Post Reply Bookmark Topic Watch Topic
    • New Topic
    Boost this thread!