Tips and Tidbits from someone Sun felt was Certifiable

Today | ???common.rss??? | ???common.rdf??? | ???common.atom??? | ???common.other???
 

There always seems to be a lot of confusion over the usage of pre/post inc/decrement operators. Of course, most of this confusion comes from people trying to prepare for the SCJP exam. The way I'm going to show these operators being used is not the way they are, or should, be used. However, if you want to prepare for the SCJP, I suggest you understand this stuff.

Throughout this post, keep in mind what the various operators do. A pre-increment operator takes the current value of the variable, increments it, and then uses the new value in the place of the expression. Meanwhile, a post-increment operator uses the current value of the variable in the expression and then increments the value. The decrement operators behave the same way except that they decrement the values rather than increments them. Here are a few examples:


int x = 0;
int y = 0;

// This evaluates to y = 0 and x is then incremented to 1.
y = x++; 

// This evaluates to y = 2 as x is incremented first and
// then inserted.
y = ++x; 

// This first decrements x to 1 and then uses it to 
// evaluate this statement to y = 1.
y = --x; 

// This statement uses the original value of x, which is 1
// to evaluate to y = 1, and then decrements x to 0.
y = x--;

Okay. With that in mind, let's look at a more thought-provoking example. Try to answer the following question (be aware that such a question is certainly fair game for the SCJP exam).


What is the result of compiling and executing the following code:



int x = 0;
int y = x++ + --x + ++x + x++ - x--;
System.out.println(x + "," + y);



A. -2,-2
B. 0,1
C. 1,0
D. 2,0
E. None of the Above

Did you get the answer? Let's go through how to solve such a problem before I reveal the correct response.

The key to solving such problems is know that operands are evaluated from left to right. Oddly enough, I had someone try to convince me otherwise once, but it's written out, clear as can be, in the JLS §15.7 Evaluation Order:

The Java programming language guarantees that the operands of operators appear to be evaluated in a specific evaluation order, namely, from left to right.

So, with that in mind, let's step through the process of evaluating this statement. We'll evaluate each operand, from left to right, one at a time.


Step 0: y = x++ + --x + ++x + x++ - x--;  // x = 0
Step 1: y =  0  + --x + ++x + x++ - x--;  // x = 1
Step 2: y =  0  +  0  + ++x + x++ - x--;  // x = 0
Step 3: y =  0  +  0  +  1  + x++ - x--;  // x = 1
Step 4: y =  0  +  0  +  1  +  1  - x--;  // x = 2
Step 5: y =  0  +  0  +  1  +  1  -  2;   // x = 1

With the operands fully evaluated, we see that x = 1 and y = 0.

So, that leaves C as the correct answer. Did you get it right?

Let's try another one.


What is the result of compiling and executing the following code:




int x = 0;
x = ++x + x++ + x-- - ++x + x++ + ++x;
System.out.println(x);



A. 0
B. 4
C. 5
D. 6
E. None of the Above

Okay, did you get this one? Once again, before I give you the answer, let's work through the solution. We'll do it just as we did before, evaluating each operand from left to right, one at a time.


int i = 0;
for (; i < 12;)
{
    i = i++;
}
System.out.println(i);

Then you'll see some sort of question like "What is the value of i when the loop terminates?" or some such thing. Well, as you should now recognize, that loop will never terminate. Rather, i will constantly flip between 0 and 1. With each iteration of the loop, you'll increment i using the post-increment operator, but you'll then immediately assign the previous value of i, which is 0, back to i. That prevents i from ever reaching 12 and the loop runs indefinitely.

Like I said earlier, this is not how you should be using these operators. In general, you want a maximum of 1 side effect per expression. When you have more than that, it is confusing. Going back to the JLS section I pointed out earlier, this is the following line:

It is recommended that code not rely crucially on this specification. Code is usually clearer when each expression contains at most one side effect, as its outermost operation, and when code does not depend on exactly which exception arises as a consequence of the left-to-right evaluation of expressions.

This is just another case (one of many) in which studying for the SCJP exam will teach you what you can do with Java but not at all what you should do with Java.

Yeah, I know, it's another lengthy post. One of these days, I promise, I'll come up with a tip that's short and sweet - just you wait. ;) Hopefully, you found this helpful.

Corey


You shouldn't be writing statements with side effects. You shoudl write statements that clearly do what they are intended to do and mixing in all that post/pre increment crap is just confusing and pointless. I've NEVER had an issue with it, because I don't write code like the type you are showing in this post. Anyone who even writes y = ++x; shoudl be shot. Increment x before or after you set y's value, according to your intention. Then it is crystal clear and no one has to decode anything.
Writing code with side effects is not (in my opinion) poor programming, as long as it is kept simple. I have no problem with someone writing this:

for ( int i = 0; i < MAX; i++ )

In that case, we're using the side-effect of the post-increment operator to cycle through a loop. I see no problem with doing so - it is clear and straight-forward. I find the alternative:

for ( int i = 0; i < MAX; i = i + 1 )

more confusing simply because it is not "the norm." When you read a sentence, you look for "structure" as well as content. When the structure is "odd," (different than what was expected), it's more difficult to read. Certainly, you can go "too far" with side effects. I propose that you use them only when it is clear and obvious that you are doing so.

Now, as far as your statement goes, I'd like to point out that I never said you should write code like this. Rather, I tried to point out the exact opposite. Code like this should be avoided. However, for purposes of studying for the SCJP exam, you need to understand what is happening so that you can answer such questions. The question isn't really testing your knowledge of pre and post increment operators (although you must understand them to get the question correct). Rather, it is testing your knowledge of the fact that operands are evaluated left to right. That piece of knowledge is very important to any programmer.
Cory, I thought your explinations were very clear. I don't know what they dudes problem is :). And as you said, code shouldn't be written like this, but to understand these operators, sometimes you have to express them in poor ways to get the point across. Well Done!!
Yes. I agree with Gregg. You have done really a wonderful job there. i have practiced well all these stuff when i was using C. Its been years that i have seen them(to this extent, ofcourse). Thanks for the blog and thank you Corey for the good stuff you are posting here..Well Done!!!
TrackBack to http://radio.javaranch.com/corey/addTrackBack.action?entry=1082478396000