Subscribe to ...considered harmful        RSS Feed
***** 3 Votes

++ considered hazardous

Icon 2 Comments
The postincrement (++) and postdecrement (--) operators (hereafter called "postinc" and "postdec") are a perennial source of befucklement for new and intermediate Java programmers. In particular, people get snagged on complex expressions that don't evaluate the way they ought to, and stupid brain teasers from programming books. There is a simple rule which will spare you all of the pain. The rule is this:

In Java, avoid the postincrement and postdecrement operators except in the stereotyped contexts of loop control or accumulation of a tally, and never use them in the context of a complex expression.

For you C users, you can do what you like. I don't do C, I don't know what C requires, I'm not talking about C. But in Java, I know that you never need to use a post-increment in a complex expression, and if you do, you deserve what you get.


Okay, that being said, let's think about why this rule makes sense, and particularly what "simple expression" means here.


First of all, let's be clear on what an expression is. In Java, an expression is a thing that returns a value. 3 is an expression (a simple integer literal), and "Foo" (a slightly more complicated String literal), and i + j % k + i * 17 is a complex expression that returns some numeric value whose type depends on the types in the expression - it'll be the highest type represented here. (we'll talk about promotion another time)

This is different from a statement. A statement, most particularly, does not return a value! It's a little beyond my current scope to define a statement, but let's just use some examples: a while loop is a statement, and the condition that governs that loop is an expression.
 
if ( something ) {
  a = "foo";
}
else {
  a = "bar";
}


is a statement (the whole thing is a statement, with nested statements!).

a = something? "foo" : "bar";


is an assignment statement, but the part to the right of the equal sign:

something? "foo" : "bar";


is an expression.

So we have an idea of what an expression is. What is a simple expression? A simple expression as I'm using it here is an expression which has no subexpressions except for literals or variables. That is, it's an expression in which precedence cannot come into play. Suppose i and j are ints, and have got the values 1 and 2 already. In that case

i 


is a simple expression which, when found on the right-hand side of an equal sign, evaluates in this case to the value 1.

i+j


is a simple expression which evaluates to the sum of the values of i and j, in this case a total of 3.

i + j * 7


is not a simple expression, because it evaluates to a multiplication of an expression by a literal. Precedence has come into the picture.

Similarly none of these are simple:

i + i + j
i * i * j
i / (j + i)


and so forth. You get the picture.

So why are complex expressions so hard to deal with in this case? Put simply, it's because the postinc (and its cousin the postdec) has two effects which do not take place "at the same time", and it's difficult to reason about what is happening when in the case of postdec in a complex expression. To be more concrete, the expression i++ has a value, and it has an effect. The value of the expression is the current value of i. In this case, that value is 1 (see above): if i == 1 and you assign some variable to the value of i++ it will get the value 1.

i++ also has an effect, and that is to increase the value of i by 1. This happens after the expression is evaluated - whatever that means. In the simple expression, it's easy to know what that means: it means that if you do k = i++ then, among other things, k + 1 == 1 will return true. But what's trickier is when exactly we get to "after" in the case of a tongue-twister like

int q = x + x++ - --x -x-- + y==x?x--:x++;


You could probably work out exactly what should happen here for any particular values of x and y, but the point is, you shouldn't use expressions that require you to do that much research and experimentation, because even if you know exactly what this means and why you did it that way, the next person looking at this won't, and they'll break your code.

So just don't do it. There's absolutely no point in using the postinc and postdec operators in java, except for a few stereotyped situations.

One safe case is in the definition of a for loop.

for (int i = 0; i < items.length; i++) {
  processItem (items[i]);
}


A for loop uses a postinc for the increment step. It's just traditional, and it would look wrong to do it otherwise, so go ahead and do the postinc. It is perfectly safe.

Another safe case is if you're accumulating a count.

while (thereAreThings()) {
  theNextThing = getTheNextThing();
  if (theNextThing == theOtherThing)
    sames++;
}


Again, this is a stereotyped usage, and it's what people expect, and again it's perfectly safe, so go ahead and use it.

Any other case where the postinc is used for its side effect and not evaluated for its return value is also safe.

Cases where a postinc is used for its side effect and also evaluated are safe if the postinc appears in a simple expression.

Cases where a postinc is used in a complex expression should be avoided at all costs, and when found they should be considered as buggy and replaced with safe code as soon as possible.

2 Comments On This Entry

Page 1 of 1

KnifeTea Icon

21 January 2014 - 12:52 AM
Nice one Jon! I understood this, so it must be pretty well written :bigsmile:
0

AfterBurner66 Icon

22 January 2014 - 09:51 AM
Absolutely agree. If you want just to take the value of postincrement or postdecrement then it's ok. When you do assignment to another variable or expression you leave something hovering in the air, right off the bat. And if you use it in a complex expression you just trust the laws of randomness.
0
Page 1 of 1

Trackbacks for this entry [ Trackback URL ]

There are no Trackbacks for this entry

Recent Entries

July 2014

S M T W T F S
  12345
6789101112
13141516171819
20212223 24 2526
2728293031