1

Can someone explain this to me? First of all, I know why this code

String getName(){
    for(;;){}
}

will violate a return type method: it's infinite, but why does this code need a final return value?

String getName(){
    for(;i < limit; i++){// i is already defined
        if(someArrayList.get(i).isDead)
            continue;
        return someArrayList.get(i).name;
    }
    //needs a final return
}

The return value exists inside the loop and returns the value for the getName() method, so what is the reason? another post suggested that what if the loop is negative for my condition, so I rewrote it this way:

String getName(){
    for(; i < 10; i++){// i is already defined
        if((i+1) == limit){
            if(!someArrayList.get(i).isDead)
                return "";
        }else{
            if(someArrayList.get(i).isDead)
                continue;
            return someArrayList.get(i).name;
        }
    }
    // needs a final return
}

The same compile time error, even if I re-define i in the for loop condition, to 0, so my i becomes zero and if the inner condition checks out negative I handle it myself. All in all, if I nest it in an infinite loop, it's ok.

String getName(){
    for(;;){
        for(; i < limit; i++){// i is already defined
            if(someArrayList.get(i).isDead)
                continue;
            return someArrayList.get(i).name;
        }
    }
}

Is it because it has a range? Because I feel it covers all scenarios, I just want to know why, before I add the last returnand life's good

And lastly this works alright:

String getName(){
    for(;;){
        for(; i < limit; i++){// i is already defined
            if(someArrayList.get(i).isDead)
                continue;
            return someArrayList.get(i).name;
        }
        return "";
    }
}

Mr. skeet says this type of code is ok in java

Community
  • 1
  • 1
  • 1
    What if `i` is already past the `limit` (or `10`) initially? Unless `i`'s value can be determined at compile time, you need a final return because the loop may *never* run. And the compiler probably does not try very hard to pinpoint the possible ranges of `i`. – dhke Jul 09 '15 at 20:20
  • i also changed that code to `for(int i =0; i < 10; i++)` and still that error, and also 10 was because i wanted to be specific but my range is a limit which the user might choose and prior to that i am checking if the limit is not the size of the arraylist.@dhke –  Jul 09 '15 at 20:33

4 Answers4

6

You need a final return statement because your list may consist only of 'dead' entries, in which case your program will reach the 'limit' and exit the for loop.

I see the comments here, so a clarification is needed. The compiler simply cannot analyze all potential outcomes and decide with 100% certainty whether the loop will reach its natural end or not. It's theoretically impossible (you can read about The Halting Problem for more information).

While the compiler can figure it out sometimes, it usually only attempts to do that in relatively simple cases. The reason behind it is simple - if your code is complex enough so that it's unclear whether the loop ends or not - it'll confuse a human reader who won't understand why there's no return statement after the loop. Such code is bad code.

zmbq
  • 38,013
  • 14
  • 101
  • 171
  • 1
    And more specifically: the Java compiler will not try and attempt to analyse every possible permutation of state. If its limited code analysis cannot prove your return is *always* executed then it has no choice but to err on the side of caution and reject your code. – user268396 Jul 09 '15 at 20:17
  • @user268396 but it does not reject infinite loops that is what i do not get, if you can take infinite loops in a return method why not allow a complex return loop? –  Jul 09 '15 at 20:37
  • thanks for your answer Mr.Zmbg, i see, so why does the compiler allow infinite loops in a return method? it is the same as that or? if its willing to risk that, why not this? at the end of the day my program will crash or mul function not the compiler or jvm –  Jul 09 '15 at 20:42
  • 1
    It doesn't reject infinite loops, it doesn't trust them to provide a return value when the only return is inside a conditional block, see my answer for more details. – Kelly S. French Jul 09 '15 at 20:54
  • 1
    The compiler is not *willing to risk* things, flow analysis covers some constructs but others are not covered. The default java compiler seems to ignore fixed variable values but it has support for loops without breaks and stop conditions. As said, he compiler does not handle every corner case just those implemented in the flow analyzer. – dhke Jul 09 '15 at 20:57
2

Because you can break from a loop. Generally you have to return something, that's what is expected to happen. Compiler is not a magician and cannot state if your loop condition is infinite or not (at least in most cases), in general it is run-time dependant.

Chlorek
  • 138
  • 7
  • but if i add break to the fourth example instead of return it causes the same compile error even if its an infinite loop –  Jul 09 '15 at 20:38
  • Well and what would you expect? ;_; Then there is not return statement at all. – Chlorek Jul 09 '15 at 21:17
2

NP Hard

Short version, what you are asking the computer to do is not just complicated or difficult but so hard there is a special term for it NP Hard, and has fairly good coverage here on Stack Overflow, see 'NP Hard vs NP Complete', or this question about proving the halting problem is NP Hard, or this question on Mathematics Stack Overflow , and last but not least see Wikipedia for the general definition of NP Hard. the compiler doesn't trust a conditional block and wants there to be a path to a return statement that doesn't depend on that conditional block.

The Curse of Turing

Long version, when the compiler evaluates the paths through the code, it creates a structure called a lattice to track all the different paths through the method. In the case where a method requires a return value the compiler uses the lattice by starting at the method exit point and examines all backwards paths looking for a return value. Yes your loop has a return statement but the compiler can't know in advance that your conditional block will always exit so it disregards that block when looking for the return value.

See the Halting Problem which actually address some of your examples but make sure you check out this answer which is my favorite simply for its charm. Your claim that the compiler should be able to tell that the loop will exit has merit if the compiler were to be coded to look for those specific code idioms; but that's the problem, there are too many special cases to code for making for a bloated compiler if that were attempted. So it generalizes the case and ignores conditional blocks when looking for a path to a return value.

Solution

What Jon Skeet said was it was ok to have more than one exit point in a method, he did not say it was ok to only have one exit point inside the conditional block.

There is a reason you see the following version of your code, it provides a default path for the return value, this is just one way to provide it.

String getName(){

    // default return value
    String retVal = "";

    for(;i < limit; i++){// i is already defined
        if(someArrayList.get(i).isDead)
            continue;
        return someArrayList.get(i).name;
    }

    //needs a final return
    return retVal;
}

When you say about the following code,

will violate a return type method: it's infinite, but why does this code need a final return value?

String getName(){
    for(;;){}
}

I would point out that the code requires one by defining a return value in the method declaration, so the following will not cause a compile error

void getName(){
    for(;;){}
}

and the question comes back to you as why you insist on declaring that a method must return something while also insisting on only using structures bounded by conditional blocks so the compiler can't detect that they will always execute.

Question

My question to you is why you don't just use a default return value, is there some reason you seem to be avoiding this approach? Not that it matters to me but it helps to know whether you have a pragmatic challenge like a coding standard or if it's more of a philosophic objection.

Community
  • 1
  • 1
Kelly S. French
  • 12,198
  • 10
  • 63
  • 93
  • 1
    hmmm i guess there is more to it that just for loops, i need time to accumulate all theses thanks Mr.French, back to add the final return, also to your question no, i was just took that approach because at first i had an if else code which was a simple yes/no return and from the little reading i have done from your links, it halts, so the compiler had no problem with it, then i jumped into pushing more codes to it, and it was undecisive, guess its not that smart ): hehe, that is why i just use that approach, thanks, –  Jul 09 '15 at 21:09
  • Sorry to nitpick, but that halting problem is not NP Hard. It's not even in R. – zmbq Jul 09 '15 at 21:56
  • 1
    It is NP Hard, [what it is not is NP Complete](https://en.wikipedia.org/wiki/NP-hard). I'll add more links about this because I didn't want that point to distract from the OP's question. – Kelly S. French Jul 09 '15 at 22:13
1

if i = 11 before you call getName(), it will never enters the loop, so it needs a return outside of it

EDIT:

String getName(){
for(; i < 10; i++){// i is already defined
    if((i+1) == limit){
        if(!someArrayList.get(i).isDead)
            return "";

        // MISSING else STATEMENT HERE
        // If when i == 9 the execution reach this point, 
        // it will jump to ----(portal)
    }else{
        if(someArrayList.get(i).isDead)
            continue;  // ALSO HERE, if i == 9 it continues, and then it jumps to ----(portal)
        return someArrayList.get(i).name;
    }
}
// needs a final return

// (portal)----> here. Needs return statement
}
Christopher Francisco
  • 15,672
  • 28
  • 94
  • 206