Sunday, September 4, 2011

The pitfalls of compound assignment operators

Compound assignment operators

You may well know, that in Java (assuming x and y are int variables), instead of writing
    x = x + y;
you can use
    x += y;

The shortcut form is called compound assignment operator and it exists for a lot of operators. They seem harmless enough at first sight.

Now look at this:
    int x = 5, y = 3;
    x *= y + 1;
    System.out.println(x);
You may think that the second line is equivalent to x = x * y + 1, but it is not. It is equivalent to x = x * (y + 1). Therefore x becomes 5 * (3 + 1), i.e. 20.

Short circuit evaluation

Short circuit evaluation describes the fact, that in Java (and many other languages) a boolean expression is only evaluated as long as its final result is not yet known.
    boolean result = true && foo(); // foo gets called
vs.
    boolean result = false && foo(); // foo gets not called
You can (and should) use that to your advantage: Cheap operations to the left, expensive ones to the right (in case of &&, it is the other way round for ||). It also common to use short circuit evaluation for precondition checking:
    boolean result = x != null && x.getMyBool();
If x is really null, we must not call the getMyBool method as it would throw a NullPointerException.

The misleading &= operator

Back to compound assignment operators, there is a &= operator. At first sight, it looks like you could abbreviate
    keep = keep && foo();
by
    keep &= foo();
But, alas, you loose short circuit evaluation, because that really means
    keep = keep & foo();
And the & operator has no short circuit evaluation.

This can be detrimental to the performance of your code, e.g. in cases like this:
   keep &= expensiveOperation1(); 
   keep &= expensiveOperation2(); 
   keep &= expensiveOperation3(); 
   keep &= expensiveOperation4(); 
Or outright fatal, if an operation must not be called
   Object x = null;
   boolean keep = x != null;
   keep &= x.toString().isEmpty();
And there is no &&= compound assignment operator. 

Conclusion

It makes me wonder whether the comfort of saving a few keystrokes and having slightly more compact code to read outweighs these pitfalls and the increased complexity of the language.