Reputation: 1217
Why is the following code giving me an error?
int n = 30000; // Some number
for (int i = 0;
0 <= n ? (i < n) : (i > n);
0 <= n ? (i++) : (i--)) { // ## Error "not a statement" ##
f(i,n);
}
Upvotes: 29
Views: 2933
Reputation:
Your code is giving you an error mostly because you're trying to solve your problem with invalid algorithm. The fact that JLS doesn't allow ternary as a condition in for loop doesn't help either - but the main problem is that you miss the valid solution of the task at hand.
Let's start with a common statement, prematureOptimization == sqrt(sum(evil))
- first you should consider what you want to do, not how to do it or why the code doesn't work.
the loop should just execute n times, using i as a counter
i step should be 1 if n is >= 0, otherwise -1
(side note: if n is invariant (and it is here) using e.g. abs(n) or n < 0 in the condition is a bad practice; although most compiler will try to factor the invariant out of the loop, you should usually simply use a temporary var to store the result and use the result in the comparison instead)
So, the code at hand should be:
void doSomething( int n ) {
if ( n >= 0 )
for( int i = 0; i < n; i++ )
f( i, n );
else
for( int i = 0; i > n; i-- )
f( i, n );
}
Factoring out invariants and separating distinct code branches are basic techniques used to increase algorithms efficiency (not a premature optimization, mind me); there's no faster nor more clean way to do this. Some may argue this is a case of loop unwinding - it very well would be, if not for the fact that those two loops shouldn't be wound together in the first place...
Another thing: third op in for loop was always an ordinary statement; let's try to guess why doesn't the following code compile?
0 <= n ? (i++) : (i--); // error: not a statement
... maybe because following code won't compile either?
0 <= n ? i : i; // error: not a statement
... and that's for the very same reason code below won't work in Java either?
i; // error: not a statement
Your answer is: ternary is not a statement - ternary just returns the value, and value is not a statement (at least in Java); i++
and i--
are allowed in ternary just because they return a value, but they also produce side effects here.
Upvotes: 4
Reputation: 53462
It's because the for
loop has been defined that way in the Java Language Specification.
14.14.1 The basic for statement
BasicForStatement:
for ( ForInit ; Expression ; ForUpdate ) Statement
ForStatementNoShortIf:
for ( ForInit ; Expression ; ForUpdate ) StatementNoShortIf
ForInit:
StatementExpressionList
LocalVariableDeclaration
ForUpdate:
StatementExpressionList
StatementExpressionList:
StatementExpression
StatementExpressionList , StatementExpression
So it needs to be a StatementExpression
or multiple StatementExpression
s, and StatementExpression
is defined as:
StatementExpression:
Assignment
PreIncrementExpression
PreDecrementExpression
PostIncrementExpression
PostDecrementExpression
MethodInvocation
ClassInstanceCreationExpression
0 <= n ? (i++) : (i--)
is none of those, so it is not accepted. i += ((0 <= n) ? 1 : -1)
is an assignment, so it works.
Upvotes: 47
Reputation: 659974
First of all, I would recommend against writing the code this way. The purpose of the code is "count up from zero to n if n is positive, count down from 0 to n if n is negative", but I would be inclined to instead write:
for (int i = 0; i < abs(n); i += 1)
{
int argument = n < 0 ? -i : i;
f(argument, n);
}
But that does not answer your question, which is:
Why can't I use
?:
operators in the 3rd argument of for loops in Java?
A for
loop has the structure for ( initialization ; condition ; action )
.
The purpose of an expression is to compute a value.
The purpose of a statement is to take an action.
There are some expressions which by design both compute a value and take an action. i++
, i += j
, new foo()
, method()
and so on.
It is bad style to have any other expression that both computes a value and takes an action. Such expressions are difficult to reason about.
Therefore the action of the for
loop is restricted to be only those expressions which by design both compute a value and take an action.
Basically, by forbidding this code the compiler is telling you that you've made a bad stylistic choice. b?i++:i--
is a legal expression but it is really bad style because it makes what is supposed to be computing a value into producing a side effect and ignoring the value.
Upvotes: 23
Reputation: 3778
replace
0 <= n ? (i++) : (i--)
with
i += ((0 <= n) ? 1 : -1)
that should work
Upvotes: 17