Why Dead Code Warning? - java

i have:
if (Constants.IS_LIVE_MOD == false)
account = Constants.OM_ACCOUNT;
else
account = "abc";
i am getting a dead code warning on 'else'. Why is it so and wat is the solution for it. Please help.

I assume the IS_LIVE_MOD constant is a final variable that is declared as false, if so then the variable is always false and can't be changed, and so the else statement will never be invoked. Therefore it is dead code.
E.g.
private static final boolean MY_VAR = false;
if(MY_VAR == false) {
System.out.println("Always does this");
}
else {
System.out.println("Dead code");
}

If IS_LIVE_MOD is a compile-time constant with the value false, the compiler knows that the "else" path will never be taken, so gives you a warning. (The Java language specification guarantees that it won't be an error, but it's reasonable to warn you.)

if Constants.IS_LIVE_MOD is a constant and its value is false than the compiler knows that else would never be executed.
You can't have it as a constant.

You're are comparing two constants (Constants.IS_LIVE_MOD and false) with each other. As they are constant, the result can be determined at compile time. So the compiler can tell which part will never be executed.

It implies that
Constants.IS_LIVE_MOD
is always equal to false; so the else clause is never executed; hence the dead code warning.

The condition if (Constants.IS_LIVE_MOD == false) always evaluates as true. Therefore else is never reached.

The meaning of the warning should be clear: the code will not be executed - is dead - since IS_LIVE_MOD is a constant, but here is one solution (workaround):
if (!Constants.IS_LIVE_MOD)
account = Constants.OM_ACCOUNT;
else
account = "abc";
or
if (Constants.IS_LIVE_MOD)
account = "abc";
else
account = Constants.OM_ACCOUNT;
Details JLS 14.21: Unreachable Statements
If you remove the comparison, the compiler recognizes that as a "conditional compilation" and does not show that warning.
Rationale (JLS):
in order to allow the if statement to be used conveniently for "conditional compilation" purposes

If Constants.IS_LIVE_MOD is constant (as its name implies) and is false, then the else clause can never possibly run; this makes it dead code.

How is Constants.IS_LIVE_MOD declared? If it's a final field, it's a good chance that the compiler optimizes this expression to be always true.

I'd say the most efficient way of writing this would be like this:
account = Constants.IS_LIVE_MOD ? "abc"
: Constants.OM_ACCOUNT;

Since IS_LIVE_MOD is a constant, the compiler figures out that it will also be false, and that the else part will never be used (until you change your Constants, then it will be the other way around).
Don't worry about it. Ignore or suppress the warning (#SuppressWarnings("all") on the method, unfortunately has to be all, I think).
If you have "real" dead code, it will make an error.

I guess Constants.IS_LIVE_MOD is a compile time constant with the value set to false. iow it becomes
if (false == false)
account = Constants.OM_ACCOUNT;
else
account = "abc";
You can just ignore the warning since Java doesn't seem to support conditional compilation Java conditional compilation: how to prevent code chunks from being compiled?

Related

Strange Java function - missing return statement [duplicate]

I encountered a situation where a non-void method is missing a return statement and the code still compiles.
I know that the statements after the while loop are unreachable (dead code) and would never be executed. But why doesn't the compiler even warn about returning something? Or why would a language allow us to have a non-void method having an infinite loop and not returning anything?
public int doNotReturnAnything() {
while(true) {
//do something
}
//no return statement
}
If I add a break statement (even a conditional one) in the while loop, the compiler complains of the infamous errors: Method does not return a value in Eclipse and Not all code paths return a value in Visual Studio.
public int doNotReturnAnything() {
while(true) {
if(mustReturn) break;
//do something
}
//no return statement
}
This is true of both Java and C#.
Why would a language allow us to have a non-void method having an infinite loop and not returning anything?
The rule for non-void methods is every code path that returns must return a value, and that rule is satisfied in your program: zero out of zero code paths that return do return a value. The rule is not "every non-void method must have a code path that returns".
This enables you to write stub-methods like:
IEnumerator IEnumerable.GetEnumerator()
{
throw new NotImplementedException();
}
That's a non-void method. It has to be a non-void method in order to satisfy the interface. But it seems silly to make this implementation illegal because it does not return anything.
That your method has an unreachable end point because of a goto (remember, a while(true) is just a more pleasant way to write goto) instead of a throw (which is another form of goto) is not relevant.
Why doesn't the compiler even warn about returning something?
Because the compiler has no good evidence that the code is wrong. Someone wrote while(true) and it seems likely that the person who did that knew what they were doing.
Where can I read more about reachability analysis in C#?
See my articles on the subject, here:
ATBG: de facto and de jure reachability
And you might also consider reading the C# specification.
The Java compiler is smart enough to find the unreachable code ( the code after while loop)
and since its unreachable, there is no point in adding a return statement there (after while ends)
same goes with conditional if
public int get() {
if(someBoolean) {
return 10;
}
else {
return 5;
}
// there is no need of say, return 11 here;
}
since the boolean condition someBoolean can only evaluate to either true or false, there is no need to provide a return explicitly after if-else, because that code is unreachable, and Java does not complain about it.
The compiler knows that the while loop will never stop executing, hence the method will never finish, hence a return statement is not necessary.
Given your loop is executing on a constant - the compiler knows that it's an infinite loop - meaning the method could never return, anyway.
If you use a variable - the compiler will enforce the rule:
This won't compile:
// Define other methods and classes here
public int doNotReturnAnything() {
var x = true;
while(x == true) {
//do something
}
//no return statement - won't compile
}
The Java specification defines a concept called Unreachable statements. You are not allowed to have an unreachable statement in your code (it's a compile time error). You are not even allowed to have a return statement after the while(true); statement in Java. A while(true); statement makes the following statements unreachable by definition, therefore you don't need a return statement.
Note that while Halting problem is undecidable in generic case, the definition of Unreachable Statement is more strict than just halting. It's deciding very specific cases where a program definitely does not halt. The compiler is theoretically not able to detect all infinite loops and unreachable statements but it has to detect specific cases defined in the specification (for example, the while(true) case)
The compiler is smart enough to find out that your while loop is infinite.
So the compiler cannot think for you. It cannot guess why you wrote that code. Same stands for the return values of methods. Java won't complain if you don't do anything with method's return values.
So, to answer your question:
The compiler analyzes your code and after finding out that no execution path leads to falling off the end of the function it finishes with OK.
There may be legitimate reasons for an infinite loop. For example a lot of apps use an infinite main loop. Another example is a web server which may indefinitely wait for requests.
In type theory, there is something called the bottom type which is a subclass of every other type (!) and is used to indicate non-termination among other things. (Exceptions can count as a type of non-termination--you don't terminate via the normal path.)
So from a theoretical perspective, these statements that are non-terminating can be considered to return something of Bottom type, which is a subtype of int, so you do (kind of) get your return value after all from a type perspective. And it's perfectly okay that it doesn't make any sense that one type can be a subclass of everything else including int because you never actually return one.
In any case, via explicit type theory or not, compilers (compiler writers) recognize that asking for a return value after a non-terminating statement is silly: there is no possible case in which you could need that value. (It can be nice to have your compiler warn you when it knows something won't terminate but it looks like you want it to return something. But that's better left for style-checkers a la lint, since maybe you need the type signature that way for some other reason (e.g. subclassing) but you really want non-termination.)
There is no situation in which the function can reach its end without returning an appropriate value. Therefore, there is nothing for the compiler to complain about.
Visual studio has the smart engine to detect if you have typed a return type then it should have a return statement with in the function/method.
As in PHP Your return type is true if you have not returned anything. compiler get 1 if nothing has returned.
As of this
public int doNotReturnAnything() {
while(true) {
//do something
}
//no return statement
}
Compiler know that while statement itself has a infinte nature so not to consider it. and php compiler will automatically get true if you write a condition in expression of while.
But not in the case of VS it will return you a error in the stack .
Your while loop will run forever and hence won't come outside while; it will continue to execute. Hence, the outside part of while{} is unreachable and there is not point in writing return or not. The compiler is intelligent enough to figure out what part is reachable and what part isn't.
Example:
public int xyz(){
boolean x=true;
while(x==true){
// do something
}
// no return statement
}
The above code won't compile, because there can be a case that the value of variable x is modified inside the body of while loop. So this makes the outside part of while loop reachable! And hence compiler will throw an error 'no return statement found'.
The compiler is not intelligent enough (or rather lazy ;) ) to figure out that whether the value of x will be modified or not. Hope this clears everything.
"Why doesn't the compiler even warn about returning something? Or why would a language allow us to have a non-void method having an infinite loop and not returning anything?".
This code is valid in all other languages too (probably except Haskell!). Because the first assumption is we are "intentionally" writing some code.
And there are situations that this code can be totally valid like if you are going to use it as a thread; or if it was returning a Task<int>, you could do some error checking based on the returned int value - which should not be returned.
I may be wrong but some debuggers allow modification of variables. Here while x is not modified by code and it will be optimized out by JIT one might modify x to false and method should return something (if such thing is allowed by C# debugger).
The specifics of the Java case for this (which are probably very similar to the C# case) are to do with how the Java compiler determines if a method is able to return.
Specifically, the rules are that a method with a return type must not be able to complete normally and must instead always complete abruptly (abruptly here indicating via a return statement or an exception) per JLS 8.4.7.
If a method is declared to have a return type, then a compile-time
error occurs if the body of the method can complete normally.
In other words, a method with a return type must return only by using
a return statement that provides a value return; it is not allowed to
"drop off the end of its body".
The compiler looks to see whether normal termination is possible based on the rules defined in JLS 14.21 Unreachable Statements as it also defines the rules for normal completion.
Notably, the rules for unreachable statements make a special case just for loops that have a defined true constant expression:
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.
So if the while statement can complete normally, then a return statement below it is necessary since the code is deemed reachable, and any while loop without a reachable break statement or constant true expression is considered able to complete normally.
These rules mean that your while statement with a constant true expression and without a break is never considered to complete normally, and so any code below it is never considered to be reachable. The end of the method is below the loop, and since everything below the loop is unreachable, so is the end of the method, and thus the method cannot possibly complete normally (which is what the complier looks for).
if statements, on the other hand, do not have the special exemption regarding constant expressions that are afforded to loops.
Compare:
// I have a compiler error!
public boolean testReturn()
{
final boolean condition = true;
if (condition) return true;
}
With:
// I compile just fine!
public boolean testReturn()
{
final boolean condition = true;
while (condition)
{
return true;
}
}
The reason for the distinction is quite interesting, and is due to the desire to allow for conditional compilation flags that do not cause compiler errors (from the JLS):
One might expect the if statement to be handled in the following
manner:
An if-then statement can complete normally iff at least one of the
following is true:
The if-then statement is reachable and the condition expression is not
a constant expression whose value is true.
The then-statement can complete normally.
The then-statement is reachable iff the if-then statement is reachable
and the condition expression is not a constant expression whose value
is false.
An if-then-else statement can complete normally iff the then-statement
can complete normally or the else-statement can complete normally.
The then-statement is reachable iff the if-then-else statement is
reachable and the condition expression is not a constant expression
whose value is false.
The else-statement is reachable iff the if-then-else statement is
reachable and the condition expression is not a constant expression
whose value is true.
This approach would be consistent with the treatment of other control
structures. However, in order to allow the if statement to be used
conveniently for "conditional compilation" purposes, the actual rules
differ.
As an example, the following statement results in a compile-time
error:
while (false) { x=3; } because the statement x=3; is not reachable;
but the superficially similar case:
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.
Why does the conditional break statement result in a compiler error?
As quoted in the loop reachability rules, a while loop can also complete normally if it contains a reachable break statement. Since the rules for the reachability of an if statement's then clause do not take the condition of the if into consideration at all, such a conditional if statement's then clause is always considered reachable.
If the break is reachable, then the code after the loop is once again also considered reachable. Since there is no reachable code that results in abrupt termination after the loop, the method is then considered able to complete normally, and so the compiler flags it as an error.

Is there any reason for Eclipse showing assignment variables in while loops as valid?

I've been punked numerous times while working on Java in eclipse when I write a while loop like so:
while (recsFinished = true)
When in reality I wanted
while (recsFinished == true)
It's a pretty simple mistake, but it happens to me a lot and it totally throws off the program. And the reason it does is because Eclipse doesn't even throw up a warning when I write the assignment as opposed to the equality equation. This leads me to believe there has to be some reason for a while loop with an assignment equation to exist, but why? I can't think of a single use!
Such assignments are popular in C and C++ (particularly within if statments) and have found themselves part of Java too.
Some folk put the literal on the left hand side: while (true == recsFinished) instead and I'm tempted to suggest that you adopt this programming style only that I personally find it obfuscating. This will issue a compiler error if = is used by accident.
Note well though that comparison to true is redundant. Drop it entirely and use while (recsFinished) instead.
It compiles, since it's valid Java syntax.
It's equivalent to :
recsFinished = true;
while (recsFinished) {
....
recsFinished = true;
}
Which is equivalent to
recsFinished = true;
while (true) {
....
recsFinished = true;
}
which would give you an infinite loop.
It is entirely possible to set a value in the expression of you while loop. If you do this your expression will be evaluated which is alway true because you reset it to true everytime you do a loop.
In most programming languages, the operator = return the assigned value after calling it.
whcih means if you want to assign a variable in every iteration and the value of this variable is the condition then you will use = in the loop condition instead of ==
Example
boolean a, b;
b = true;
while(a = b){
// Some crazy things using a & b
// loop ends when b == false at the end of an iteration
}
To answer your question; It's valid because the specification says so.
You can call a method with an expression,
15.12. Method Invocation Expressions
A method invocation expression is used to invoke a class or instance method.
MethodInvocation:
MethodName ( ArgumentList opt )
ArgumentList:
Expression
ArgumentList , Expression
and an assignment is an expression,
15.26. Assignment Operators
There are 12 assignment operators; all are syntactically right-associative (they group right-to-left). Thus, a=b=c means a=(b=c), which assigns the value of c to b and then assigns the value of b to a.
AssignmentExpression:
ConditionalExpression
Assignment

Using objects/variables initialized inside a loop?

I declare my objects outside of an if statement, but initialize them inside of it. Later I try and use them but it won't allow it because they haven't been initialized. The if statements are structured so that they all will execute before the objects are used, and hence the objects will be initialized guaranteed, but java doesn't allow that. Any way around this?
If you know that all paths will ultimately initialize them, but the compiler doesn't, you can initialize them to null or 0 or false (as ajb helpfully reminds) -- or some other special initial value you define -- when declaring them. They then have a concrete initial value.
If the variable is still null (or whatever it's initial value was) by the time you use it (evidenced perhaps by an NPE in the case of an object) then you know something went wrong; you can also self-document your assumptions with asserts later.
You should post your code so we can give you better advice; the compiler is relatively smart about path analysis, although it can't, of course, handle cases that rely on external input or assumed preconditions and invariants. Still, it's always possible that you've overlooked something (perhaps an exception or unexpected condition leads to a path where the value is uninitialized - which is fine, you just have to make sure it's initialized).
The only way an object's initialization is guaranteed after a conditional expression is if there exists a branch that is always executed, such as an else statement, or default in switch statements.
To decompose that, take this example code:
String word;
String name = "Peter";
if("Peter".equals(name)) {
word = "The Bird";
}
System.out.println(word);
This will fail since the compiler identifies a branch in which word is not initialized.
If you add an else clause, then the compiler will believe that word is initialized.
String word;
String name = "Peter";
if("Peter".equals(name)) {
word = "The Bird";
} else {
word = "Nope";
}
System.out.println(word);
Java requires that a variable be initialized along all possible paths to the point of use before its value can be referenced. Eg, if you have
int x;
if (a == b) {
x = 5;
}
if (c == d) {
x = 6;
}
int y = x;
In the above case the compiler cannot know that either the first or second if statement will be true, and so it's not certain that x gets assigned a value along all paths leading to the assignment to y. So the compiler will disallow this (and, if the compiler didn't reject this, the "verifier" inside the JVM would).
The solution is to assign a value to the variable (maybe zero or -1 in this case, null for an object reference) so that it's known to have a value along all paths.
But note that you probably should not just assign a dummy value to every variable you declare, since very often the compiler message that no value is assigned can indicate a real live code bug where you've accidentally omitted assigning a value to the variable along some path.
initialize them to null
Object myAwesomesauceVariableOfAwesome = null;
if(myUnbelievablyWildBoolean){
myAwesomesauceVariableOfAwesome = getAwesomesauce();
}
doSomethingCompletelyMindBlowingWithAwesomesauce(myAwesomesauceVariableOfAwesome);

Confusing while block

The following code block gives me a compile time error.
while(false)
{
System.out.println("HI");
}
The error says that there is an unreachable statement.
BUT the following code compiles
boolean b=false;
while(b)
{
System.out.println("Hi");
}
All i could think of was this -> In case-1 as false is a literal so the compiler finds that its unreachable and in case 2 variable b in while condition block is checked at runtime so there is no compilation error?
The compiler writers do not get to decide which conditions to flag as errors - the rules are in the Java Language Specification, for this issue in 14.21 Unreachable Statements.
The relevant sentence is: "The contained statement is reachable iff the while statement is reachable and the condition expression is not a constant expression whose value is false."
In each case, you have a reachable while statement. In the first version, false is a constant expression whose value is false, so the contained statement is not considered reachable. In the second version, b is not a constant expression at all, so the contained statement is treated as being reachable.
Adding final to the declaration of b changes the while condition to a constant expression whose value is false, making the contained statement unreachable again.
Specifying the rules for what is and is not a compile time error in the JLS has the benefit that all Java compilers should accept the same set of programs. The rules generally do not require the compiler to do data flow analysis, presumably to limit the cost and difficulty of writing compilers.
The compiler sees while(false), which will never be true, so you cannot reach the println. This throws an error.
Meanwhile, although while(b) will never be true either, the compiler doesn't automatically know this, because b isn't automatically false, it is a boolean that happens to have the value false, it could change at some point. (It doesn't here, but it could have).
To make this point more general, the compiler will look at the type of a variable, but not what the variable actually is. Many beginning programming classes have sections which deal with how polymorphism and type casting leads to run-time errors in some cases, and compiler errors in others. If you happen to have taken a course such as these, you can think of your question here as having a similar explanation.
This makes sense to me. While (false) will never evaluate successfully, whereas in the case of while(b) - the value of b could be updated to true at some point in the program's lifetime.
The compiler isn't extremely smart about things. It'll find a block where you have a provably false condition, and it'll cry. Give it something like this, and javac isn;t wired to look even that far. Tings obvious to humans are not necessarily obvious to computers, and vice versa.
Compiler sees while(false) and can determine that block inside while won't execute ever.
while in case of boolean, value of b evaluated at runtime so it won't stop you

Lazy evaluation not working as it should

I had to evaluate a boolean expression frecuently, so I converted it in a private method in it's class. Here is the code it's causing me trouble:
//"x", "y" and "team" are already defined
return (map.isWalkable(x,y) &&
(!map.isOccupied(x,y) || map.getOccupant(x, y).getTeam() == team) );
Methods should be preety much self-explanatory as for the purpose of this question. Now, isWalkable and isOccupied both return a boolean, and getOccupant is the only method returning an object reference. The problem is that I'm getting a NullPointerException when executing this piece of code, and that shouldn't be happening because isOccupied returns true if and only if map.getOccupant != null (that's actually what that method returns). So with a language supporting lazy boolean evaluation from left to right (as I assume java is, or at least that's what I was able to read) the getOccupant method should never be executed whenever it would return null am I right?
Is this more compiler-dependent than I thought it was? Should it be safer if I used if statements, or is there simply something obvious I'm missing here, maybe operations get resolved the other way round.
The issue is your parenthesis. Try
return (map.isWalkable(x,y) && (!map.isOccupied(x,y) || map.getOccupant(x, y).getTeam() == team));
Simply put, no, lazy evaluation is not broken. Your code is.
Either map is null, or map.getOccupant(x,y) returns null.
If you put them on their own lines and go through them with a debugger, you'll notice that "oh no, I was so stupid and didn't notice that".
The compiler, JVM or anything else has nothing to do with this.

Categories

Resources