Sunday, May 27, 2012

Why does this go into an infinite loop?


I'm a teacher, and yesterday a student wrote the following code:




public class Tests {
public static void main(String[] args) throws Exception {
int x = 0;
while(x<3) {
x = x++;
System.out.println(x);
}
}
}



We know he should have writen just x++ or x=x+1 , but on x = x++; it should first attribute x to itself, and later increment x. Why does x continue with 0 as value?



--update



Here's the bytecode:




public class Tests extends java.lang.Object{
public Tests();
Code:
0: aload_0
1: invokespecial #1; //Method java/lang/Object."<init>":()V
4: return

public static void main(java.lang.String[]) throws java.lang.Exception;
Code:
0: iconst_0
1: istore_1
2: iload_1
3: iconst_3
4: if_icmpge 22
7: iload_1
8: iinc 1, 1
11: istore_1
12: getstatic #2; //Field java/lang/System.out:Ljava/io/PrintStream;
15: iload_1
16: invokevirtual #3; //Method java/io/PrintStream.println:(I)V
19: goto 2
22: return

}



I'll read about the instructions to try to understand...


Source: Tips4all

25 comments:

  1. Perhaps if we write out a method to do the equivalent of what x++ does it will make this clearer.

    (Note: this is C# code for the purpose of illustration. Unless I'm mistaken there's actually no way to pass a parameter by reference in Java.)

    public static int PostIncrement(ref int x)
    {
    int valueBeforeIncrement = x;
    x = valueBeforeIncrement + 1;
    return valueBeforeIncrement;
    }


    Right? Increment the value passed and return the original value: that's the definition of the postincrement operator.

    Now, let's see how this behavior plays out in your example code:

    int x = 0;
    x = PostIncrement(ref x);


    PostIncrement(ref x) does what? Increments x, yes. And then returns what x was before the increment. This return value then gets assigned to x.

    So the order of values assigned to x is 0, then 1, then 0.

    This might be clearer still if we re-write the above:

    int x = 0; // x is 0.
    int temp = PostIncrement(ref x); // Now x is 1, and temp is 0.
    x = temp; // Now x is 0 again.


    Your fixation on the fact that when you replace x on the left side of the above assignment with y, "you can see that it first increments x, and later attributes it to y" strikes me as confused. It is not x that is being assigned to y; it is the value formerly assigned to x. Really, injecting y makes things no different from the scenario above; we've simply got:

    int x = 0; // x is 0.
    int y = 0; // y is 0.
    int temp = PostIncrement(ref x); // Now x is 1, and temp is 0.
    y = temp; // y is still 0.


    So it's clear: x = x++ effectively does not change the value of x. It always causes x to have the values x0, then x0 + 1, and then x0 again.



    Update: Incidentally, lest you doubt that x ever gets assigned to 1 "between" the increment operation and the assignment in the example above, I've thrown together a quick demo to illustrate that this intermediate value does indeed "exist," though it will never be "seen" on the executing thread.

    The demo calls x = x++; in a loop while a separate thread continuously prints the value of x to the console.

    The code is in Java, but I warn you: I have basically zero experience in Java (I only even answered this question because I felt I could explain what was happening with the ++ operator). So this code might be hideous to a seasoned Java developer.

    public class Main {
    public static volatile int x = 0;

    public static void main(String[] args) {
    LoopingThread t = new LoopingThread();
    System.out.println("Starting background thread...");
    t.start();

    while (true) {
    x = x++;
    }
    }
    }

    class LoopingThread extends Thread {
    public @Override void run() {
    while (true) {
    System.out.println(Main.x);
    }
    }
    }


    Below is an excerpt of the above program's output. Notice the occasional occurrence of 1 amongst a flurry of 0s.


    Starting background thread...
    0
    0
    1
    1
    0
    0
    0
    0
    0
    0
    0
    0
    0
    0
    1
    0
    1

    ReplyDelete
  2. x = x++ works in the following way:


    First it evaluates expression x++. Evaluation of this expression produces an expression value (which is the value of x before increment) and increments x.
    Later it assigns the expression value to x, overwriting incremented value.


    So, the sequence of events looks like follows (it's an actual decompiled bytecode, as produced by javap -c, with my comments):

    8: iload_1 // Remember current value of x in the stack
    9: iinc 1, 1 // Increment x (doesn't change the stack)
    12: istore_1 // Write remebered value from the stack to x


    For comparison, x = ++x:

    8: iinc 1, 1 // Increment x
    11: iload_1 // Push value of x onto stack
    12: istore_1 // Pop value from the stack to x

    ReplyDelete
  3. This happens because the value of x doesn't get incremented at all.

    x = x++;


    is equivalent to

    int temp = x;
    x++;
    x = temp;


    Explanation:

    Let's look at the byte code for this operation. Consider a sample class:

    class test {
    public static void main(String[] args) {
    int i=0;
    i=i++;
    }
    }


    Now running the class disassembler on this we get:

    $ javap -c test
    Compiled from "test.java"
    class test extends java.lang.Object{
    test();
    Code:
    0: aload_0
    1: invokespecial #1; //Method java/lang/Object."<init>":()V
    4: return

    public static void main(java.lang.String[]);
    Code:
    0: iconst_0
    1: istore_1
    2: iload_1
    3: iinc 1, 1
    6: istore_1
    7: return
    }


    Now the Java VM is stack based which means for each operation, the data will be pushed onto the stack and from stack the data will popped out to perform the operation. There is also another data structure, typically an array to store the local variables. The local variables are given ids which are just the indexes to the array.

    Let us look at the mnemonics in main() method:


    iconst_0: The constant value 0
    is pushed on to the stack.
    istore_1: The top element of the
    stack is popped out and stored in the
    local variable with index 1 which
    is x.
    iload_1 : The value at the
    location 1 that is value of x
    which is 0, is pushed into the
    stack.
    iinc 1, 1 : The value at the
    memory location 1 is
    incremented by 1. So x now becomes
    1.
    istore_1 : The value at the top of
    the stack is stored to the memory
    location 1. That is 0 is assigned
    to x overwriting its incremented value.


    Hence the value of x does not change resulting in the infinite loop.

    ReplyDelete
  4. Prefix notation will increment the variable BEFORE the expression is evaluated.
    Postfix notation will increment AFTER the expression evaluation.


    However "=" has a lower operator precedence than "++".

    So x=x++; should evaluate as follows


    x prepared for assignment (evaluated)
    x incremented
    Previous value of x assigned to x.

    ReplyDelete
  5. None of the answers where quite spot on, so here goes:

    When you're writing int x = x++, you're not assigning x to be itself at the new value, you're assigning x to be the return value of the x++ expression. Which happens to be the original value of x, as hinted in Colin Cochrane's answer .

    For fun, test the following code:

    public class Autoincrement {
    public static void main(String[] args) {
    int x = 0;
    System.out.println(x++);
    System.out.println(x);
    }
    }


    The result will be

    0
    1


    The return value of the expression is the initial value of x, which is zero. But later on, when reading the value of x, we receive the updated value , that is one.

    ReplyDelete
  6. It has been already explained well by other. I just include the links to the relevant Java specification sections.

    x = x++ is an expression. Java will follow the evaluation order.
    It will first evaluate the expression x++, which will increment x and set result value to the previous value of x.
    Then it will assign the expression result to the variable x. At the end, x is back at its previous value.

    ReplyDelete
  7. This statement:

    x = x++;


    evaluates like this:


    Push x onto the stack;
    Increment x;
    Pop x from the stack.


    So the value is unchanged. Compare that to:

    x = ++x;


    which evaluates as:


    Increment x;
    Push x onto the stack;
    Pop x from the stack.


    What you want is:

    while (x < 3) {
    x++;
    System.out.println(x);
    }

    ReplyDelete
  8. From http://download.oracle.com/javase/tutorial/java/nutsandbolts/op1.html


    The increment/decrement operators can
    be applied before (prefix) or after
    (postfix) the operand. The code
    result++; and ++result; will both end
    in result being incremented by one.
    The only difference is that the prefix
    version (++result) evaluates to the
    incremented value, whereas the
    postfix version (result++) evaluates
    to the original value. If you are
    just performing a simple
    increment/decrement, it doesn't really
    matter which version you choose. But
    if you use this operator in part of a
    larger expression, the one that you
    choose may make a significant
    difference.


    To illustrate, try the following:

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


    Which will print 1 and 0.

    ReplyDelete
  9. You're effectively getting the following behavior.


    grab the value of x (which is 0) as "the result" of the right side
    increment the value of x (so x is now 1)
    assign the result of the right side (which was saved as 0) to x (x is now 0)


    The idea being that the post-increment operator (x++) increments that variable in question AFTER returning its value for use in the equation it's used in.

    Edit: Adding a slight bit because of the comment. Consider it like the following.

    x = 1; // x == 1
    x = x++ * 5;
    // First, the right hand side of the equation is evaluated.
    ==> x = 1 * 5;
    // x == 2 at this point, as it "gave" the equation its value of 1
    // and then gets incremented by 1 to 2.
    ==> x = 5;
    // And then that RightHandSide value is assigned to
    // the LeftHandSide variable, leaving x with the value of 5.

    ReplyDelete
  10. You don't really need the machine code to understand what's happending.

    According the definitions:


    The assignment operator evaluates the right-hand side expression, and stores it in a temporary variable.

    1.1. The current value of x is copied into this temporary variable

    1.2. x is incremented now.
    The temporary variable is then copied into the left-hand side of the expression, which is x by chance! So that's why the old value of x is again copied into itself.


    It is pretty simple.

    ReplyDelete
  11. This is because it never gets incremented in this case. x++ will use the value of it first before incrementing like on this case it will be like:

    x = 0;


    But if you do ++x; this will increase.

    ReplyDelete
  12. The value stays at 0 because the value of x++ is 0. In this case it doesn't matter if the value of x is increased or not, the assignment x=0 is executed. This will overwrite the temporary incremented value of x (which was 1 for a "very short time").

    ReplyDelete
  13. The answer is pretty straightforward. It has to do with the order things are evaluated. x++ returns the value x then increments x.

    Consequently, the value of the expression x++ is 0. So you are assigning x=0 each time in the loop. Certainly x++ increments this value, but that happens before the assignment.

    ReplyDelete
  14. This works how you expect the other one to. It's the difference between prefix and postfix.

    int x = 0;
    while (x < 3) x = (++x);

    ReplyDelete
  15. Think of x++ as a function call that "returns" what X was before the increment (that's why it's called a post-increment).

    So the operation order is:
    1: cache the value of x before incrementing
    2: increment x
    3: return the cached value (x before it was incremented)
    4: return value is assigned to x

    ReplyDelete
  16. When the ++ is on the rhs, the result is returned before the number is incremented.
    Change to ++x and it would have been fine.
    Java would have optimised this to perform a single operation (the assignment of x to x) rather than the increment.

    ReplyDelete
  17. x++
    =: (x = x + 1) - 1


    So:

    x = x++;
    => x = ((x = x + 1) - 1)
    => x = ((x + 1) - 1)
    => x = x; // Doesn't modify x!


    Whereas

    ++x
    =: x = x + 1


    So:

    x = ++x;
    => x = (x = x + 1)
    => x = x + 1; // Increments x


    Of course the end result is the same as just x++; or ++x; on a line by itself.

    ReplyDelete
  18. x = x++; (increment is overriden by = )


    because of above statement x never reaches 3;

    ReplyDelete
  19. I wonder if there's anything in the Java spec that precisely defines the behavior of this. (The obviously implication of that statement being that I'm too lazy to check.)

    Note from Tom's bytecode, the key lines are 7, 8 and 11. Line 7 loads x into the computation stack. Line 8 increments x. Line 11 stores the value from the stack back to x. In normal cases where you are not assigning values back to themselves, I don't think there would be any reason why you couldn't load, store, then increment. You would get the same result.

    Like, suppose you had a more normal case where you wrote something like:
    z=(x++)+(y++);

    Whether it said (pseudocode to skip technicalities)

    load x
    increment x
    add y
    increment y
    store x+y to z


    or

    load x
    add y
    store x+y to z
    increment x
    increment y


    should be irrelevant. Either implementation should be valid, I would think.

    I'd be extremely cautious about writing code that depends on this behavior. It looks very implementation-dependent, between-the-cracks-in-the-specs to me. The only time it would make a difference is if you did something crazy, like the example here, or if you had two threads running and were dependent on the order of evaluation within the expression.

    ReplyDelete
  20. I think because in Java ++ has a higher precedence than = (assignment)...Does it?
    Look at http://www.cs.uwf.edu/~eelsheik/cop2253/resources/op_precedence.html...

    The same way if you write x=x+1...+ has a higher precedence than = (assignment)

    ReplyDelete
  21. The x++ expression evaluates to x. The ++ part affect the value after the evaluation, not after the statement. so x = x++ is effectively translated into

    int y = x; // evaluation
    x = x + 1; // increment part
    x = y; // assignment

    ReplyDelete
  22. Well as far as I can see, the error occurs, due to the assignment overriding the incremented value, with the value prior to incrementation, i.e. it undoes the increment.

    Specifically, the "x++" expression, has the value of 'x' prior to increment as opposed to "++x" which has the value of 'x' after incrementation.

    If you are interested in investigating the bytecode, we will take a look at the three lines in question:

    7: iload_1
    8: iinc 1, 1
    11: istore_1


    7: iload_1 # Will put the value of the 2nd local variable on the stack
    8: iinc 1,1 # will increment the 2nd local variable with 1, note that it leaves the stack untouched!
    9: istore_1 # Will pop the top of stack and save the value of this element to the 2nd local variable
    (You can read the effects of each JVM instruction here)

    This is why the above code will loop indefinitely, whereas the version with ++x will not.
    The bytecode for ++x should look quite different, as far as I remember from the 1.3 Java compiler I wrote a little over a year ago, the bytecode should go something like this:

    iinc 1,1
    iload_1
    istore_1


    So just swapping the two first lines, changes the semantics so that the value left on the top of stack, after the increment (i.e. the 'value' of the expression) is the value after the increment.

    ReplyDelete
  23. The increment operator is applied to the same variable as you are assigning to. That's asking for trouble. I am sure that you can see the value of your x variable while running this program.... that's should make it clear why the loop never ends.

    ReplyDelete
  24. Before incrementing the value by one, the value is assigned to the variable.

    ReplyDelete
  25. It's happening because it's post incremented. It means that the variable is incremented after the expression is evaluated.

    int x = 9;
    int y = x++;


    x is now 10, but y is 9, the value of x before it was incremented.

    See more in Definition of Post Increment.

    ReplyDelete