89

I often find when debugging a program it is convenient, (although arguably bad practice) to insert a return statement inside a block of code. I might try something like this in Java ....

class Test {
        public static void main(String args[]) {
                System.out.println("hello world");
                return;
                System.out.println("i think this line might cause a problem");
        }
}

of course, this would yield the compiler error.

Test.java:7: unreachable statement

I could understand why a warning might be justified as having unused code is bad practice. But I don't understand why this needs to generate an error.

Is this just Java trying to be a Nanny, or is there a good reason to make this a compiler error?

Cœur
  • 37,241
  • 25
  • 195
  • 267
Mike
  • 58,961
  • 76
  • 175
  • 221
  • 13
    Java isn't entirely consistent about this either. For some control flows that cause dead code, but Java doesn't complain. For others it does. Determining what code is dead is an uncomputable problem. I don't know why Java decided to start something it couldn't finish. – Paul Draper Mar 21 '13 at 20:11

8 Answers8

65

Because unreachable code is meaningless to the compiler. Whilst making code meaningful to people is both paramount and harder than making it meaningful to a compiler, the compiler is the essential consumer of code. The designers of Java take the viewpoint that code that is not meaningful to the compiler is an error. Their stance is that if you have some unreachable code, you have made a mistake that needs to be fixed.

There is a similar question here: Unreachable code: error or warning?, in which the author says "Personally I strongly feel it should be an error: if the programmer writes a piece of code, it should always be with the intention of actually running it in some scenario." Obviously the language designers of Java agree.

Whether unreachable code should prevent compilation is a question on which there will never be consensus. But this is why the Java designers did it.


A number of people in comments point out that there are many classes of unreachable code Java doesn't prevent compiling. If I understand the consequences of Gödel correctly, no compiler can possibly catch all classes of unreachable code.

Unit tests cannot catch every single bug. We don't use this as an argument against their value. Likewise a compiler can't catch all problematic code, but it is still valuable for it to prevent compilation of bad code when it can.

The Java language designers consider unreachable code an error. So preventing it compiling when possible is reasonable.


(Before you downvote: the question is not whether or not Java should have an unreachable statement compiler error. The question is why Java has an unreachable statement compiler error. Don't downvote me just because you think Java made the wrong design decision.)

Community
  • 1
  • 1
SamStephens
  • 5,721
  • 6
  • 36
  • 44
  • 23
    _Obviously the language designers of Java agree_ "Language designers of Java" are humans and prone to mistakes too. Personally, I feel that other side in the discussion you refer has much stronger arguments. – Nikita Rybak Sep 25 '10 at 21:30
  • 2
    I don't think this explains why "meaningless" code is sufficient to justify a compiler error, which would normally be reserved for syntax issues. – Mike Sep 25 '10 at 21:34
  • @bolt but do any generate errors for issues that aren't related to syntax? – Mike Sep 25 '10 at 21:37
  • 1
    for final production code, yes. during development, absolutely disagree. – Brady Moritz Sep 25 '10 at 21:39
  • Well this is the thing, isn't it. There's no objective way to say warning or error is better, it comes down to personal opinion. C#'s take is its a warning. My take is that the UI design principle of designing an interface to prevent incorrect input entirely applies to languages either. What does an unreachable statement mean? If its a copy and paste error, we want to be forced to fix it. If the code is intended to be there, it isn't meaningful to the compiler, is therefore there for developers, and can therefore be a comment. – SamStephens Sep 25 '10 at 21:40
  • 1
    @Mike: Compilers prevent all sorts of things that aren't syntax related - access to uninitialized variables to name a small example. – SamStephens Sep 25 '10 at 21:41
  • 4
    @Mike: Java spits [a plethora of compile-time errors](http://mindprod.com/jgloss/compileerrormessages.html) that aren't always related to syntax. For instance, forgetting to override abstract methods, attempting to catch exceptions that are never thrown from their try blocks, etc. – BoltClock Sep 25 '10 at 21:41
  • 1
    SamStephens: It sounds like you've argued against any sort of compiler warning. I don't see why something completely harmless needs to be an error. – Gabe Sep 25 '10 at 23:11
  • 6
    @Gabe: Because it's not harmless - it's almost certainly a mistake. Either you've put your code in the wrong place, or misunderstood that you've written your statement in such a way that some of it can't be reached. Making this an error prevents incorrect code from being written, and if you want something in an unreachable place in your code for other developers to read (the only audience for unreachable code), use a comment instead. – SamStephens Sep 25 '10 at 23:27
  • SamStephens: What qualifies as a compiler warning to you? – Gabe Sep 26 '10 at 00:01
  • @Gabe: My personal opinion is that warnings should be used for constructs that should be tidied, but are most likely not indicative of an actual error in coding. Uncalled private methods and unused variables are two I can think of. However, the real answer is that a compiler warning is anything a language designer decides is a warning! – SamStephens Sep 26 '10 at 00:43
  • 10
    SamStephens: Seeing as how uncalled methods and unused variables are essentially all forms of unreachable code. Why allow some forms and not others? In particular, why disallow such a useful debugging mechanism? – Gabe Sep 26 '10 at 01:25
  • @Gabe: Interesting question. For me personally, I still think unreachable code is much more likely to indicate a coding fault than an unused method or variable. However, like I said, it's not something there's a hard and fast answer to, and it's up to the language designer to decide whether warning or error is best for their language. – SamStephens Sep 26 '10 at 01:48
  • 6
    Aren't comments also unreachable? In my mind, unreachable code is actually a form of comments (this is what I was trying to do earlier, etc). But considering "real" comments aren't "reachable" either... maybe they should also raise this error ;) – Brady Moritz Jan 30 '12 at 00:50
  • Comments are not code, and are not intended for consumption by the compiler - they are for human consumption only. There's no need to allow code that is only intended for documentation purposes, as we have other means of doing this. I still stand by my earlier comment "What does an unreachable statement mean? If its a copy and paste error, we want to be forced to fix it. If the code is intended to be there, it isn't meaningful to the compiler, is therefore there for developers, and can therefore be a comment" Really it's up to language designers to decide. If you don't like, use something else – SamStephens Jan 30 '12 at 03:52
  • 3
    I feel you're missing the point. Something's definitely wrong if there's unreachable code, but that doesn't mean the code can't be executed anyway, which can be useful in debugging. And as long as the compiler still screams "warning" every time it comes across such a problem, isn't that enough? – dhardy Jun 06 '12 at 08:36
  • Again, it's a matter of opinion. As you say, "something's definitely wrong if there's unreachable code". Sure a program can be executed when there's unreachable code. But executable code is a minimum standard - good languages try to force you towards correct code. Java takes the point of view that unreachable code is incorrect enough that you should be forced to fix it before compiling. Warning is good enough for the authors of the C# compiler. It isn't for Java's authors. Java reflects the philosophies of its authors, and those philosophies are legitimate. – SamStephens Jun 07 '12 at 11:01
  • 10
    The problem is that they (java language designers) are inconsistent with this. If there is actual flow analysis, it's trivial to realize that both `return; System.out.println();` and `if(true){ return; } System.out.println();` are guaranteed to have the same behavior, but one is a compile error, and the other is not. So, when I'm debugging, and I use this method to "comment out" code temporarily, that's how I do it. The problem with commenting out code is that you have to find the appropriate place to stop your comment, which may take longer than throwing in a `return;` real quick. – LadyCailin Sep 19 '12 at 21:48
  • 2
    Having unused code doesn't merrit an error IMHO. A warning at the very most would be nice. What if I have something unfinished. I don't want to remove it just because it's unreachable. – trusktr Oct 02 '13 at 04:52
  • 1
    Why not let the designers of Java write "correct" code and let those who don't wish to do so not do so? Just because a language doesn't enforce "correct" reachable code doesn't mean people with philosophies like the creators of Java have to write incorrect code. – trusktr Oct 02 '13 at 04:56
  • 3
    Meaningless from the point of view of compiler != meaningless from the point of view of developers. Compile error on unreachable code is the stupidest thing I saw recently. – enrey Nov 29 '13 at 00:38
  • @enrey, my comment from Sep 25 '10 at 21:40 on this answer covers your point I think. – SamStephens Nov 29 '13 at 21:57
  • 2
    @SamStephens "it's almost certainly a mistake"... "Almost certainly" isn't very certain, and for things that are "probably error", compiler has warnings. Plain return in middle of a function is almost never an error though, it's being done all the time on purpose. Why don't we use comments? Comments don't nest, so you can't just enclose the rest of a function in block comment if there are some other block comments already. You have to write some stupid workaround like `if(true)return;` which looks far more like an error, produces no warning and is more likely to be forgotten in the end. – enrey Nov 30 '13 at 15:17
  • 1
    Since SamStephens explicitly asks for downvote explanations: "*Unreachable code is meaningless, and therefore an error.*" was enough for me to push that down arrow. `for(int i=0;i<5; i++){}` is meaningless but produces no error (not even a warning, nothing). And I see no reason meaningless code would be an error. Actually, all debug paterns are meaningless in the terms of function. And I intended to use `return;` to break function sooner than expected for debug purposes. – Tomáš Zato Feb 03 '15 at 03:06
  • Thanks @TomášZato, you've spurred me to rewrite this answer with a lot more clarity. – SamStephens Feb 04 '15 at 06:02
49

There is no definitive reason why unreachable statements must be not be allowed; other languages allow them without problems. For your specific need, this is the usual trick:

if (true) return;

It looks nonsensical, anyone who reads the code will guess that it must have been done deliberately, not a careless mistake of leaving the rest of statements unreachable.

Java has a little bit support for "conditional compilation"

http://java.sun.com/docs/books/jls/third_edition/html/statements.html#14.21

if (false) { x=3; }

does not result in a compile-time error. An optimizing compiler may realize that the statement x=3; will never be executed and may choose to omit the code for that statement from the generated class file, but the statement x=3; is not regarded as "unreachable" in the technical sense specified here.

The rationale for this differing treatment is to allow programmers to define "flag variables" such as:

static final boolean DEBUG = false;

and then write code such as:

if (DEBUG) { x=3; }

The idea is that it should be possible to change the value of DEBUG from false to true or from true to false and then compile the code correctly with no other changes to the program text.

irreputable
  • 44,725
  • 9
  • 65
  • 93
  • 2
    Still don't get why you'd bother with the trick you show. Unreachable code is meaningless to the compiler. So the only audience for it is developers. Use a comment. Although I guess if you're adding a return in temporarily, using your workaround might be fractionally quicker than just putting in a return, and commenting out the following code. – SamStephens Sep 26 '10 at 03:07
  • 8
    @SamStephens But everytime you wanted to switch you would have to remember all the places where you have to comment out code and where you have to do the opposite. You would have to read through the whole file, changing the source code, probably making some subtle mistakes every now and then instead of just replacing "true" with "false" at one place. I think it's better to code the switching logic once and don't touch it unless necessary. – Robert Jun 21 '12 at 19:02
  • "anyone who reads the code will guess that it must have been done deliberately". This is exactly the problem in my opinion, people shouldn't be guessing, they should understand. Remembering code is communication with people, not just instructions for computers. If it's anything other than extremely temporary, you should be using configuration in my opinion. Looking at what you're showing above, `if (true) return;` doesn't indicate WHY you're skipping the logic, whereas `if (BEHAVIOURDISABLED) return;` communicates intention. – SamStephens Jun 23 '12 at 02:47
  • 5
    This trick is really useful for debugging. I often add an if(true) return to eliminate "the rest" of a method trying to find out where it's failing. There are other ways, but this is clean and quick--but it's not something you should ever check in. – Bill K Jan 16 '14 at 17:56
20

It is Nanny. I feel .Net got this one right - it raises a warning for unreachable code, but not an error. It is good to be warned about it, but I see no reason to prevent compilation (especially during debugging sessions where it is nice to throw a return in to bypass some code).

Brady Moritz
  • 8,624
  • 8
  • 66
  • 100
  • 1
    java was designed way earlier, each byte counts at that time, floppy disks were still high tech. – irreputable Sep 25 '10 at 22:58
  • 1
    For the debug early return, it takes another five seconds to comment out the lines following your early return. A small price to play for the bugs prevented by making unreachable code an error. – SamStephens Sep 25 '10 at 23:31
  • 6
    it is also easy for the compiler to exclude unreachable code. no reason to force the developer to do so. – Brady Moritz Sep 26 '10 at 03:42
  • 2
    @SamStephens not if you already have comments there, since comments do not stack, it's unnecessary pain to work around this with comments. – enrey Nov 29 '13 at 00:21
  • @SamStephens Commented out code does not refactor well. – cowlinator Jul 31 '14 at 23:03
  • Why are you refactoring unreachable code? If the code has a reason to live, it should be reachable under some circumstances, even if that circumstance is a change in configuration. – SamStephens Jul 31 '14 at 23:25
  • How could java ever do anything with floppy disks with it's horrible memory usage? – Tomáš Zato Feb 03 '15 at 03:11
15

I only just noticed this question, and wanted to add my $.02 to this.

In case of Java, this is not actually an option. The "unreachable code" error doesn't come from the fact that JVM developers thought to protect developers from anything, or be extra vigilant, but from the requirements of the JVM specification.

Both Java compiler, and JVM, use what is called "stack maps" - a definite information about all of the items on the stack, as allocated for the current method. The type of each and every slot of the stack must be known, so that a JVM instruction doesn't mistreat item of one type for another type. This is mostly important for preventing having a numeric value ever being used as a pointer. It's possible, using Java assembly, to try to push/store a number, but then pop/load an object reference. However, JVM will reject this code during class validation,- that is when stack maps are being created and tested for consistency.

To verify the stack maps, the VM has to walk through all the code paths that exist in a method, and make sure that no matter which code path will ever be executed, the stack data for every instruction agrees with what any previous code has pushed/stored in the stack. So, in simple case of:

Object a;
if (something) { a = new Object(); } else { a = new String(); }
System.out.println(a);

at line 3, JVM will check that both branches of 'if' have only stored into a (which is just local var#0) something that is compatible with Object (since that's how code from line 3 and on will treat local var#0).

When compiler gets to an unreachable code, it doesn't quite know what state the stack might be at that point, so it can't verify its state. It can't quite compile the code anymore at that point, as it can't keep track of local variables either, so instead of leaving this ambiguity in the class file, it produces a fatal error.

Of course a simple condition like if (1<2) will fool it, but it's not really fooling - it's giving it a potential branch that can lead to the code, and at least both the compiler and the VM can determine, how the stack items can be used from there on.

P.S. I don't know what .NET does in this case, but I believe it will fail compilation as well. This normally will not be a problem for any machine code compilers (C, C++, Obj-C, etc.)

Pawel Veselov
  • 3,996
  • 7
  • 44
  • 62
  • How aggressive is Java's dead code warning system? Could it be expressed as part of the grammar (e.g. `{ [flowingstatement;]* }`=>`flowingstatement`, `{ [flowingstatement;]* stoppingstatement; }`=>`stoppingstatement`, `return`=>`stoppingstatement`, `if (condition) stoppingstatement; else stoppingstatement`=>`stoppingstatement;` etc.? – supercat Aug 05 '13 at 23:35
  • I'm not good with grammars, but I believe so, yes. The "stopping", however, can be local, for example a "break" statement inside a loop. Also, the end of a method is a implicit stopping statement for the method level, if the method is void. 'throw' will also be an explicit stopping statement. – Pawel Veselov Aug 06 '13 at 22:09
  • What would the Java standard say about something like `void blah() { try {return;} catch (RuntimeError ex) { } DoSomethingElse(); }` Would Java squawk that there was no way the `try` block could actually exit via an exception, or would it figure that any kind of unchecked exception could occur within any `try` block? – supercat Aug 06 '13 at 22:37
  • The best way to find out is to try and compile that. But compiler allows for even empty try/catch statements. However, any JVM instruction can theoretically throw an exception, so try block may exit so. But I'm not sure how is this relevant to this question. – Pawel Veselov Aug 06 '13 at 23:49
  • Basically, the question is whether the only forbidden "unreachable" statements are those which could be identified as unreachable on the basis of parsing, without having to actually evaluate any expressions, or whether the standard could forbid unreachable statements like `if (constantThatEqualsFive < 3) {doSomething;};`. – supercat Aug 06 '13 at 23:57
  • I just found the spec and looked it up; `if` is parsed grammatically without regard for a constant expression, but `while` actually evaluates the value. The spec doesn't say whether `x && y` is considered constant `false` and `y` isn't, but if it is that could cause some reasonable code compile or fail to do so based upon the values of constants. – supercat Aug 07 '13 at 00:06
  • Thanks for the explanation. FYI, .NET treats unreachable code as a warning. – SamStephens Aug 19 '13 at 19:57
5

While I think this compiler error is a good thing, there is a way you can work around it. Use a condition you know will be true:

public void myMethod(){

    someCodeHere();

    if(1 < 2) return; // compiler isn't smart enough to complain about this

    moreCodeHere();

}

The compiler is not smart enough to complain about that.

Sean Patrick Floyd
  • 292,901
  • 67
  • 465
  • 588
  • 6
    The question here is why? Unreachable code is meaningless to the compiler. So the only audience for it is developers. Use a comment. – SamStephens Sep 25 '10 at 21:43
  • 3
    So I get downvotes because I agree with the way the java guys desgined their compile? Jeez... – Sean Patrick Floyd Sep 25 '10 at 22:14
  • Just wait 'til I start the 'where to the brackets go' discussion. – Tony Ennis Sep 25 '10 at 22:33
  • 1
    You get downvotes for not answering the actual question. See SamStephens' comment. – BoltClock Sep 25 '10 at 22:37
  • 2
    javac can definitely infer that `1<2` is true, and the rest of the method doesn't have to be included in the byte code. the rules of "unreachable statements" must be clear, fixed, and independent of the smartness of compilers. – irreputable Sep 25 '10 at 22:49
  • Afraid not - question is why it's an error, not how to work around the error. – SamStephens Sep 26 '10 at 03:05
  • 1
    @Sam with that attitude, you're going to have to downvote 50% of the best answers of this site (and I am not saying that my answer is among those). A big part of answering questions on SO, as in any IT consulting situation, is to identify the real question (or relevant side questions) from a given question. – Sean Patrick Floyd Sep 26 '10 at 12:33
5

One of the goals of compilers is to rule out classes of errors. Some unreachable code is there by accident, it's nice that javac rules out that class of error at compile time.

For every rule that catches erroneous code, someone will want the compiler to accept it because they know what they're doing. That's the penalty of compiler checking, and getting the balance right is one of the tricker points of language design. Even with the strictest checking there's still an infinite number of programs that can be written, so things can't be that bad.

Ricky Clarkson
  • 2,909
  • 1
  • 19
  • 21
0

If the reason for allowing if (aBooleanVariable) return; someMoreCode; is to allow flags, then the fact that if (true) return; someMoreCode; does not generate a compile time error seems like inconsistency in the policy of generating CodeNotReachable exception, since the compiler 'knows' that true is not a flag (not a variable).

Two other ways which might be interesting, but don't apply to switching off part of a method's code as well as if (true) return:

Now, instead of saying if (true) return; you might want to say assert false and add -ea OR -ea package OR -ea className to the jvm arguments. The good point is that this allows for some granularity and requires adding an extra parameter to the jvm invocation so there is no need of setting a DEBUG flag in the code, but by added argument at runtime, which is useful when the target is not the developer machine and recompiling & transferring bytecode takes time.

There is also the System.exit(0) way, but this might be an overkill, if you put it in Java in a JSP then it will terminate the server.

Apart from that Java is by-design a 'nanny' language, I would rather use something native like C/C++ for more control.

MichaelS
  • 271
  • 2
  • 4
  • Changing something from a `static final` variable which is set in a static initialization block to a `static final` variable which is set in its declaration shouldn't be a breaking change. It's entirely plausible that when a class is first written it may have sometimes been unable to do something (and not known until run-time whether it would be able to do it or not), but later versions of the class might have been able to do that action always. Changing `myClass.canFoo` to a constant should make `if (myClass.canFoo) myClass.Foo(); else doSomethingElse();` more efficient--not break it. – supercat Dec 30 '13 at 19:25
0

It is certainly a good thing to complain the more stringent the compiler is the better, as far as it allows you to do what you need. Usually the small price to pay is to comment the code out, the gain is that when you compile your code works. A general example is Haskell about which people screams until they realize that their test/debugging is main test only and short one. I personally in Java do almost no debugging while being ( in fact on purpose) not attentive.