1

recently I started to do some experiments with different language compilers due to my studies in Compiler Design,

and I found a very odd thing, that happens in Java

and that is, as you may know, if we have a method with no return path, there is no requirement to return any value

So if I have the next method, this is totally fine, since this is an infinite loop

   private int Run(){
        while (true){
        }
    }

but once I but break statement anywhere even with impossible condition non-reachable area the compile complains

so the next java code will not compile

  private int Run(){
        while (true){
            if(false){
             break;
            }
        }
    }

but compared to c#

 int Run()
    {
        while (true)
        {
            if (true == false)
            {
                break;
            }
        }
    }

or c++

int Run() {
    while (true)
    {
        if (false) {
            break;
        }
    }
}

both will compile just fine, even in c# most refactoring tools say that the code is redundant because the compiler will finally eliminate it since it is a compile time constant

I think this issue is somehow related to Halting problem, but can not figure out where is the issue exactly.

so if anyone has an idea of what happening with java please tell me, Thank you.

  • 1
    It's presumably just a matter of how much flow analysis gets done in the light of compile-time constant expressions. In the Java case, there **is** a way out of the loop, it just won't ever be taken. I grant you, it's curious that the compile-time constant is handled ok in 'while' but not 'if'. I'd guess it's because 'while true' is a common idiom and worth handling. – dangling else May 21 '22 at 20:11
  • Yes. The halting problem says that you cannot always tell whether a program will finish. That goes for return path detection too. So no matter which compiler we’re talking about (this or the other Java, C++ or C# compiler), it will make an effort and catch some cases and miss others. To me it’s not a problem. If it is to you, the it’s a problem that cannot be solved. Provably. – Ole V.V. May 21 '22 at 20:12
  • 1
    Does this answer your question? [Why do I not need to provide a return value after an endless loop?](https://stackoverflow.com/questions/19952598/why-do-i-not-need-to-provide-a-return-value-after-an-endless-loop) – Progman May 21 '22 at 21:37
  • @Progman, it may be, but all people just talk, without any documentation, I know already that there is a limitation in java for this type of path tracking, but I want to know the reason behind that since there is no technical limitation , since both c++ and c# and many other languages addressed theses issues before, – Al Banna Techno logy May 21 '22 at 21:40
  • 2
    @AlBannaTechnology Have you checked the answers like https://stackoverflow.com/questions/1958563/does-java-recognize-infinite-loops/1959785#1959785 and https://stackoverflow.com/questions/1958563/does-java-recognize-infinite-loops/1958617#1958617? – Progman May 21 '22 at 21:45
  • @Progman, yah checked it, but it does not answer the reason behind that,it's like an arbitrary decision, also it says that' Except for the special treatment of while, do, and for statements whose condition expression has the constant value true', although we used 'if(true){break;}', so it should be considered as a special case, but still this not happens, it only happens with 'while', I just came across many threads, but I first explain that I am I compiler design studies, so I scoped the target audience for the question, to not conflict with other questions that asking if this is valid or not – Al Banna Techno logy May 21 '22 at 23:35
  • *I want to know the reason behind that* So you want us to be mind readers? Not going to happen. – Ole V.V. May 22 '22 at 07:34

1 Answers1

2

The behaviour if the code

private int Run(){
    while (true){
        if(false){
             break;
        }
    }
}

is a compile-error or not is defined in the Java Language Specification, specifically in Chapter 14. Blocks and Statements. Statements can "complete normally" or "complete abruptly". Based on these information, the execution of other statements are affected.

Chapter 14.15. The break Statement defines that the break statement will complete the "break target" normally:

A break statement with no label attempts to transfer control to the innermost enclosing switch, while, do, or for statement of the immediately enclosing method or initializer; this statement, which is called the break target, then immediately completes normally.

Also chapter 14.21. Unreachable Statements defines the following:

  • 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.

("iff" means "if and only if", as defined in chapter 14.21 and explained in https://en.wikipedia.org/wiki/If_and_only_if)

The first condition is false in our case as we have the condition expression true for the while loop. Notice that this section defines that a while loop with while(true) {...} without any break statements will not "complete normally".

Now we need to check if there is a "reachable" break statement. The break statement is "reachable" because of the following chain:

  • The block that is the body of a constructor, method, instance initializer, or static initializer is reachable.

The {...} block of the method.

The first statement in a non-empty block that is not a switch block is reachable iff the block is reachable.

So the while loop is reachable.

The contained statement is reachable iff the while statement is reachable and the condition expression is not a constant expression whose value is false.

As the while loop is reachable and the condition expression is not false, the inner block {...} of the while statement is reachable. The if() statement inside the {...} block is reachable again because it is the first statement in a reachable block (see above).

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

The {...} block of the if-statement is reachable, so is the first statement break of that block (see above).

Notice that the condition of the if() statement is not checked during this analysis of the compiler (as indicated in the non-normative section at the bottom of chapter 14.21).

This whole "reachable" checks means that the while loop can complete normally. This means that the {...} block of the method can complete normally, see chapter 14.2. Blocks:

If all of these block statements complete normally, then the block completes normally

And that means that a return statement is required, as chapter 8.4.7. Method Body defines it:

If a method is declared to have a return type (§8.4.5), then a compile-time error occurs if the body of the method can complete normally (§14.1).

Therefore, you need a return statement, even though you have a break statement which cannot be executed. But having the reachable break statement there changes everything. This is what is "happening with java", regardless of what C# or C++ is doing.

Progman
  • 16,827
  • 6
  • 33
  • 48