39

Possible Duplicates:
Why does this go into an infinite loop?

Things like i = i++ have undefined behavior in C and C++ because the value of a scalar object is changes twice within the same expression without intervening sequence point.

However I suppose that these kind of expressions have well-defined behavior in C# or Java because AFAIK the evaluation of argument goes left to right and there are sequence points all over.

That said, I'd expect i = i++ to be equivalent to i++. But it's not. The following program outputs 0.

using System;
class Program
{
    static void Main(string[] args)
    {
        int i = 0;
        i = i++;
        Console.WriteLine(i);
    }
}

Could you help me understand why?

Disclaimer: I am fully aware that whether or not the behavior of above-mentioned constructs is defined, they are silly, useless, unreadable, unnecessary and should not be used in code. I am just curious.

Community
  • 1
  • 1
Armen Tsirunyan
  • 130,161
  • 59
  • 324
  • 434
  • 6
    @Downvoter: Care to leave a comment? – Armen Tsirunyan Jul 16 '11 at 08:19
  • 5
    This was asked last year about Java, but answered in C# (both work similarly for this case): http://stackoverflow.com/questions/3831341/why-does-this-go-into-an-infinite-loop – BoltClock Jul 16 '11 at 09:05
  • 6
    This can't be a duplicate with the same question but a different language, since this question is about the language specification, which obviously can differ between languages. In particular the C/C++ vs. C# specifications differ. While C# and Java seem to have the same behavior in this regard, this is not obvious. – CodesInChaos Jul 16 '11 at 14:59
  • 5
    You believe a myth: that the "i++" means "the increment happens after everything else". That is simply false. In reality, *the increment happens when the expression is evaluated*! See my article on this myth for more details: http://blogs.msdn.com/b/ericlippert/archive/2009/08/10/precedence-vs-order-redux.aspx – Eric Lippert Jul 16 '11 at 18:57
  • 2
    @Eric: I must admit I intuitively thought so... In C++ you just don't know when exactly it will happen, so I assumed in C# it would be in the very end. – Armen Tsirunyan Jul 16 '11 at 19:01
  • 4
    @Armen: That is a very common misconception. See also this answer for more details: http://stackoverflow.com/questions/3346450/c-what-is-the-difference-between-i-and-i/3346729#3346729 – Eric Lippert Jul 16 '11 at 19:18

4 Answers4

47

The behavior is well defined in C# and the evaluation order is:

  1. Left side i is evaluated to the variable i
  2. Right side is evaluated to 0, and i is incremented (now i==1)
  3. The assignment is executed, it sets i to 0. (now i==0)

The end result is i==0.

In general you first create an expression tree. To evaluate it you evaluate first the left side, then the right side and finally the operation at the root. Do that recursively.

CodesInChaos
  • 106,488
  • 23
  • 218
  • 262
  • Ah! It makes sense. I'm silly :) – Armen Tsirunyan Jul 16 '11 at 08:13
  • 3
    In Java you can occasionally observe the value `1` from a parallel thread if you make `i` volatile (in my test typically 65 times in 100 million iterations). – starblue Jul 16 '11 at 09:46
  • 1
    i = ++i should work fine as well. – arkoak Jul 16 '11 at 10:06
  • 2
    @A-b `i = ++i` would result in `i` being 1 in the end. But I'm not sure what you mean by `work fine`, since this question has to specific purpose the code need to achieve. – CodesInChaos Jul 16 '11 at 10:11
  • Why is the right side evaluated to 0? And why does the right side remain zero when incremented? – Andrew J. Brehm Jul 16 '11 at 12:44
  • 3
    The *post* -increment operator `i++` operator is defined as incrementing `i` but returning the value it had before. The *pre* -increment operator `++i` on the other hand returns the incremented value. `i++` => `temp=i;i=i+1;return temp;` vs. `++i` => `i=i+1;return i;` – CodesInChaos Jul 16 '11 at 12:49
21

The result of the post-increment expression i++ is the original value of i. So after i++ has been evaluated (incrementing i), you assign the old value of i to ... i.

Just use

i++;

;)

Marc Gravell
  • 1,026,079
  • 266
  • 2,566
  • 2,900
  • 1
    I was aware of the difference of preincrement and postincrement. I was confused because I expected the side-effect of increment to take place after the evaluation of the whole expression... Obviously I was wrong – Armen Tsirunyan Jul 16 '11 at 08:24
  • @Armen yeah, c# is pretty much left-to-right – Marc Gravell Jul 16 '11 at 08:31
  • 4
    @Marc I find the formulation that an expression is evaluated left-to-right confusing. I prefer thinking about the expression as a tree which is then evaluated recursively. And each each node first evaluate its arguments left-to-right and finally executes itself. – CodesInChaos Jul 16 '11 at 09:20
18

i = ++iis the code that does what you think is going on here. i++ actually behaves a bit differently.

With i++, the value of i is increased, but the value of i++ is not the new value of i, it's the previous value. So when you do i = i++, you're saying "increase the value of i, then set i to the old value".

Jeremy
  • 1
  • 85
  • 340
  • 366
6

Well, the right-hand side expression must be evaluated before the assignment can take place. Now, i++ will evaluate to the current value of i, and i's value will subsequently increase by one. However, the assignment hasn't been performed yet, and when it is, it will overwrite the current value of i (1) with whatever the rhs expression evaluated to, which in your case was 0.

The key difference is between ++i (pre-increment, which evaluates to the new value of i after incrementing) and i++, or post-increment, which evaluates to the current value of i before incrementing.

Had you used ++i instead, the right-hand side expression would have evaluated to 1, resulting in i == 1.

Kyle
  • 21,377
  • 37
  • 113
  • 200
Martin Törnwall
  • 9,299
  • 2
  • 28
  • 35