Why does my Java compiler (jikes) reject "return;" in the middle of a method on the grounds that it makes the rest of the method unreachable, and yet not so much as warn me about " if (true) { return; }" which makes the rest of the method equally unreachable?
no subject
Date: 2003-02-07 02:49 pm (UTC)no subject
Date: 2003-02-07 06:57 pm (UTC)no subject
Date: 2003-02-07 08:36 pm (UTC)Well, sorta.
From what I've read of the Java standard and from what I've learned from people writing Java .java -> .class compilers, the standard forbids a lot of standard optimizations. From what I understand, for example, constant propagation is pretty much disallowed. That is, the following conversion is not technically kosher:
{ int z = 4; int x = z + z} --> { int x = 4 + 4; }
Which is fairly common trick combined with constant folding, which would allow the compiler to go in a chain from there to:
{ int x = 4 + 4; } --> { int x = 8; }
Seeing as constant propagation is illegal (or legal sometimes but illegal in others, in such a way that doing a good job is too hard), I suspect that most java compilers ditch constant folding, too. So when they hit something like:
if(true) { return; }
They make no effort to see if the test always fails or succeeds (dead code elimination), because programmers so rarely write such things directly. So why bother? Stupid optimizations like this tend to do very well when there's other stuff up front that converts the code into this, but since there isn't, why bother?
So, anyways, the compiler sees the if statement and splits out a new basic block for the if. The new one is entered by the test and exits at the next statement. Since there's no else, however, there's still a link from the previous block to the next block. Since the compiler doesn't know that one path is always chosen, it doesn't know the if branch dominates the rest of the code, and therefor it doesn't know that it makes the rest of the method dead code.
So anyways, part of the answer is: the java compiler is lazy because the Java standard tells it to be lazy, and thus it can't figure it out. Any optimizing compiler for basically any other language that's worth anything would notice this.
On the other hand, Java's always been way into runtime optimization stuff. So the real code optimization is supposed to come at the .class -> native stage. So, since the java .java -> .class compiler isn't going to do much in the way of optimizations anyways, why bother with some possibly expensive analyses to check for this stuff? Most Java developers like when their java programs compile as fast as possible.
Anyways, that's my explanation.
no subject
Date: 2003-02-08 08:02 am (UTC)I don't know if I think that's a good thing or a bad thing. I suppose it's good that I can't accidentally chop out half a method by putting in a poorly placed return statement. On the other hand, I only run into this situation when I'm deliberately attempting to chop out half a method.
The unreachable statement thingy also drives me nuts in switch statements because as a C programmer I learned that you always put "break" at the end of a case, but in Java you can't use "break" if you're returning from that case (which makes the break unreachable). It just looks wrong to have a switch statement with no breaks, even if I know it's not going to fall through.