Unreachable statement: while true vs if true [duplicate]
Asked Answered
S

3

10

How should I understand this Java compiler behaviour?

while (true) return;
System.out.println("I love Java");
// Err: unreachable statement

if (true) return;
System.out.println("I hate Java");
// OK.

Thanks.

EDIT:

I find out the point after a few minutes:

In the first case compiler throws error because of infinite loop. In both cases compiler does not think about the code inside the statement consequent.

EDIT II:

What impress me on javac now is:

    if (true) return; // Correct
}
    while (true) return; // Correct
}

It looks like javac knows what is inside both loop and if consequent, but when you write another command (as in the first example) you get non-equivalent behaviour (which looks like javac forgot what is inside loop/if).

public static final EDIT III: As the result of this answer I may remark (hopefully correct): Expressions as if (arg) { ...; return;} and while (arg) { ...; return;} are equivalent both semantically and syntactically (in bytecode) for Java iff argv is non-constant (or effectively final type) expression. If argv is constant expression bytecode (and behaviour) may differs.

Disclaimer This question is not on unreachable statements but different handling of logically equivalent expressions such as while true return and if true return.

Scanty answered 11/2, 2017 at 12:55 Comment(9)
It's a case of "If I write crazy code, the compiler may also act crazy".Piatt
@Andremoniy Nope. Please read carefully.Scanty
@marek094, what is your intention for such comparison? Java is not a lower level language and the so to say compiler is not a machine language compiler. What is the exact answer you are looking for, or the exact question, you intend to ask? Also, considering the number of virtual machines and compilers available today, it is so to say very generic and less informant question, in my opinion.Grearson
@SiddharthTyagi It is a preparation for my exam, where I am expected answer similar questions written on a paper. ¯_(ツ)_/¯Scanty
@Scanty sounds like OCJP or OCJD. Try to learn the rules from the jls, you only need 60% to pass (i think). After the exam you will never need it again.Crooked
The problem with your question, and the reason why @Piatt is correct is highlighted in your disclaimer. The two statements are not logically equivalent. One is a conditional, and one is a loop. They use the same keywords within their checks, but they have no where close to the same functionality, intent, or ramifications.Footway
And this is also related: Why is an if/else if/else for a simple boolean not giving an "unreachable code" errorAlkanet
@Footway There are two parts of logic - semantic and syntax. These two expressions are semantically equivalent. Syntactically - the resulting byte code equality depends on non-/constant expression in argument (as you can see in k5_ answer).Scanty
@Scanty you only have a reasonable semantic if the syntax is correct. None compilable code might have an intention of semantic, but no actual semantic.Crooked
C
14

There are quite strict rules when statements are reachable in java. These rules are design to be easily evaluated and not to be 100% acurate. It should prevent basic programming errors. To reason about reachability in java you are restricted to these rules, "common logic" does not apply.

So here are the rules from the Java Language Specification 14.21. Unreachable Statements

An if-then statement can complete normally iff it is reachable.

So without an else, statements after an if-then are always reachable

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

  • The while statement is reachable and the condition expression is not a constant expression (§15.28) with value true.

  • There is a reachable break statement that exits the while statement.

The condition is a constant expression "true", there is no break. Hence it does not complete normally.

Crooked answered 11/2, 2017 at 13:14 Comment(1)
I remember seeing rationale for this. Basic idea is that you can have if(COMPILATION_SWITCH) return; A and have program compiling properly regardless of value of the switch.Hostelry
T
5

According to the docs:

Except for the special treatment of while, do, and for statements whose condition expression has the constant value true, the values of expressions are not taken into account in the flow analysis.

Topsyturvy answered 11/2, 2017 at 13:18 Comment(0)
C
2

If you change your code slightly (remove the constant expression), so it doesnt trigger javac reachability it will actually produce identical bytecode for both.

static boolean flag = true;

static void twhile(){
    while (flag) return;
    System.out.println("Java");
}
static void tif(){
    if (flag) return;
    System.out.println("Java");
}

The resulting bytecode:

  static void twhile();
    descriptor: ()V
    flags: ACC_STATIC
    Code:
      stack=2, locals=0, args_size=0
      StackMap locals:
      StackMap stack:
     0: getstatic     #10                 // Field flag:Z
     3: ifeq          7
     6: return
      StackMap locals:
      StackMap stack:
     7: getstatic     #20                 // Field java/lang/System.out:Ljava/io/PrintStream;
    10: ldc           #26                 // String Java
    12: invokevirtual #28                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
    15: return
      LineNumberTable:
    line 8: 0
    line 9: 7
    line 10: 15
      LocalVariableTable:
    Start  Length  Slot  Name   Signature
      StackMapTable: number_of_entries = 1
    frame_type = 7 /* same */

  static void tif();
    descriptor: ()V
    flags: ACC_STATIC
    Code:
      stack=2, locals=0, args_size=0
      StackMap locals:
      StackMap stack:
     0: getstatic     #10                 // Field flag:Z
     3: ifeq          7
     6: return
      StackMap locals:
      StackMap stack:
     7: getstatic     #20                 // Field java/lang/System.out:Ljava/io/PrintStream;
    10: ldc           #26                 // String Java
    12: invokevirtual #28                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
    15: return
      LineNumberTable:
    line 12: 0
    line 13: 7
    line 14: 15
      LocalVariableTable:
    Start  Length  Slot  Name   Signature
      StackMapTable: number_of_entries = 1
    frame_type = 7 /* same */
Crooked answered 11/2, 2017 at 14:23 Comment(3)
Yeah, I read byte code for the constant-expression case and its differs which is quite obscure.Scanty
@Scanty as you didnt provide a compilable example for the constant-expression case it is hard to compare. In my tests it creates "noops" with different fluff around it.Crooked
You are right, I meant the second example from my question. I know, than it is not the same situation but also interesting.Scanty

© 2022 - 2024 — McMap. All rights reserved.