Saturday, September 1, 2012

Post-Increment Differences between C and Java

Pre/Post Increment/Decrement differences Java and C

Pre/Post Increment/Decrement differences Java and C

It turns out that Java and C implement these features very differently. The ambiguity derives from the fact that – and ++ look like ordinary arithmetic operators. However unlike +, - , * and / the – and ++ have side effects. They return a value then change a value (in the post-increment/decrement form). The timing of when the values change in an arithmetic expression is different in Java and than it is in C. I have never had a problem even when switching between C and Java programming because I limit my use of these operators to stand alone statements in loop definitions. However the issue came up for me when my son had a homework question in his AP Computer Science class.

I have never liked these operators very much. They may have made sense in an era of green screen terminals where screen space was at a premium and saving a few keystrokes meant better productivity. On today's computers circa 2012 and in an era of "documentation is an extremely important part of software development", saving few keystrokes is meainingless. Still it's part of the language and understanding it will increase your understanding of computer language design.

I will summarize my web research with a couple of examples of code but for an in depth discussion of the matter look at the following forum some of entries give references to the pertinent Java specifications. There is even an example of JVM machine code generated to implement a post-increment operation.

http://www.java-forums.org/new-java/20135-postincrement-java.html

To illustrate the problem look at the following java code:

public class PrePostIncDecTest {
  public static void main(String[] args)
  {
    int j = 2;

    System.out.println(7%3 + j++ + (j-2));
  }
}

The above code returns 4 as it's answer from the println. This is surprising as a similar C program returns 3 as would be expected under the C definition of post-increment it should return the current value then increment the variable after the statement is completed.

Naive C expectations of execution

  1. since is j=2, you would calculate the parenthesis first which evaluate to 0.
  2. Then modulus would take precedence that evaluates to 1
  3. so we are left with 1 + j++ + 0
  4. j=2 and j++ is post increment so the computer should use 2 in the calculation
  5. that would mean 1 + 2 + 0 evaluated to 3 and j is now 3 from the postincrement

So I added some more to the test program. The output was surprising in terms of how java is evaluating the expression. Giving a left to right precedence and ignoring the parenthesis. Look at the following code:

public class PrePostIncDecTest {
  public static void main(String[] args)
  {
    int j = 2;

    System.out.println(7%3 + j++ + (j-2));
    // Do it again but just add 0 don't do the parenthesis
    j = 2;
    System.out.println(1 + j++ + 0);
    j = 2;
    System.out.println(7%3 + (j-2) + j++ );
  }
}

The output of the above program is

4
3
3

Strange behavior. More surprising is the subtraction inside the parenthesis, I tend to calculate things in parenthesis first. Java worked the problem from left to right, which is OK mathematically since addition is commutative. But since there are side effects due to the post-increment the order of evaluation is important. Parenthesis (in Java it seems) do not provide enough precedence to use as a way of controlling the order of execution. The post-increment seems to be incrementing as soon as the value is used. The previously mentioned website suggests that this is necessary to provide a thread safe means of implementing increment.

Conclusion

Don't use pre-increment/decrement or post-increment/decrement in arithmetic expressions. The side effects are too ambiguous. I have always used these operations for loop control or as single statement increment/decrement. This is especially important if you span multiple C like languages. C and Java look similar but implement operations differently in some cases. Be careful when switching back and forth and develop a programming methodology that protects you from unwanted side effects.

Author: Nasty Old Dog