For i = 0, why is (i += i++) equal to 0?

C#.Net

C# Problem Overview


Take the following code (usable as a Console Application):

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

The result of i is 0. I expected 2 (as some of my colleagues did). Probably the compiler creates some sort of structure that results in i being zero.

The reason I expected 2 is that, in my line of thought, the right hand statement would be evaluated first, incrementing i with 1. Than it is added to i. Since i is already 1, it is adding 1 to 1. So 1 + 1 = 2. Obviously this is not what's happening.

Can you explain what the compiler does or what happens at runtime? Why is the result zero?

Some-sort-of-disclaimer: I'm absolutely aware you won't (and probably shouldn't) use this code. I know I never will. Nevertheless, I find it is interesting to know why it acts in such a way and what is happening exactly.

C# Solutions


Solution 1 - C#

This:

int i = 0;
i += i++

Can be seen as you doing (the following is a gross oversimplification):

int i = 0;
i = i + i; // i=0 because the ++ is a postfix operator and hasn't been executed
i + 1; // Note that you are discarding the calculation result

What actually happens is more involved than that - take a look at MSDN, 7.5.9 Postfix increment and decrement operators:

> The run-time processing of a postfix increment or decrement operation of the form x++ or x-- consists of the following steps:

> - If x is classified as a variable:

> - x is evaluated to produce the variable. > - The value of x is saved. > - The selected operator is invoked with the saved value of x as its argument. > - The value returned by the operator is stored in the location given by the evaluation of x. > - The saved value of x becomes the result of the operation.

Note that due to order of precedence, the postfix ++ occurs before +=, but the result ends up being unused (as the previous value of i is used).


A more thorough decomposition of i += i++ to the parts it is made of requires one to know that both += and ++ are not atomic (that is, neither one is a single operation), even if they look like they are. The way these are implemented involve temporary variables, copies of i before the operations take place - one for each operation. (I will use the names iAdd and iAssign for the temporary variables used for ++ and += respectively).

So, a closer approximation to what is happening would be:

int i = 0;
int iAdd = i; // Copy of the current value of i, for ++
int iAssign = i; // Copy of the current value of i, for +=

i = i + 1; // i++ - Happens before += due to order of precedence
i = iAdd + iAssign;

Solution 2 - C#

Disassembly of the running code:

int i = 0;
  xor         edx, edx
  mov         dword ptr i, edx         // set i = 0
i += i++;
  mov         eax, dword ptr i         // set eax = i (=0)
  mov         dword ptr tempVar1, eax  // set tempVar1 = eax (=0)
  mov         eax, dword ptr i         // set eax = 0 ( again... why??? =\ )
  mov         dword ptr tempVar2, eax  // set tempVar2 = eax (=0)
  inc         dword ptr i              // set i = i+1 (=1)
  mov         eax, dword ptr tempVar1  // set eax = tempVar1 (=0)
  add         eax, dword ptr tempVar2  // set eax = eax+tempVar2 (=0)
  mov         dword ptr i, eax         // set i = eax (=0)

Equivalent code

It compiles to the same code as the following code:

int i, tempVar1, tempVar2;
i = 0;
tempVar1 = i; // created due to postfix ++ operator
tempVar2 = i; // created due to += operator
++i;
i = tempVar1 + tempVar2;

Disassembly of the second code (just to prove they are the same)

int i, tempVar1, tempVar2;
i = 0;
    xor         edx, edx
    mov         dword ptr i, edx
tempVar1 = i; // created due to postfix ++ operator
    mov         eax, dword ptr i
    mov         dword ptr tempVar1, eax
tempVar2 = i; // created due to += operator
    mov         eax, dword ptr i
    mov         dword ptr tempVar2, eax
++i;
    inc         dword ptr i
i = tempVar1 + tempVar2;
    mov         eax, dword ptr tempVar1
    add         eax, dword ptr tempVar2
    mov         dword ptr i, eax

Opening disassembly window

Most people don't know, or even don't remember, that they can see the final in-memory assembly code, using Visual Studio Disassembly window. It shows the machine code that is being executed, it is not CIL.

Use this while debuging:

Debug (menu) -> Windows (submenu) -> Disassembly

So what is happening with postfix++?

The postfix++ tells that we'd like to increment the value of the operand after the evaluation... that everybody knows... what confuses a bit is the meaning of "after the evaluation".

So what does "after the evaluation" means:

  • other usages of the operand, on the same line of code must be affected:
    • a = i++ + i the second i is affected by the increment
    • Func(i++, i) the second i is affected
  • other usages on the same line respect short-circuit operator like || and &&:
    • (false && i++ != i) || i == 0 the third i is not affected by i++ because it is not evaluated

So what is the meaning of: i += i++;?

It is the same as i = i + i++;

The order of evaluation is:

  1. Store i + i (that is 0 + 0)
  2. Increment i (i becomes 1)
  3. Assign the value of step 1 to i (i becomes 0)

Not that the increment is being discarded.

What is the meaning of: i = i++ + i;?

This is not the same as the previous example. The 3rd i is affected by the increment.

The order of evaluation is:

  1. Store i (that is 0)
  2. Increment i (i becomes 1)
  3. Store value of step 1 + i (that is 0 + 1)
  4. Assign the value of step 3 to i (i becomes 1)

Solution 3 - C#

int i = 0;
i += i++;

is evaluated as follows:

Stack<int> stack = new Stack<int>();
int i;

// int i = 0;
stack.Push(0);                   // push 0
i = stack.Pop();                 // pop 0 --> i == 0

// i += i++;
stack.Push(i);                   // push 0
stack.Push(i);                   // push 0
stack.Push(i);                   // push 0
stack.Push(1);                   // push 1
i = stack.Pop() + stack.Pop();   // pop 0 and 1 --> i == 1
i = stack.Pop() + stack.Pop();   // pop 0 and 0 --> i == 0

i.e. i is changed twice: once by the i++ expression and once by the += statement.

But the operands of the += statement are

  • the value i before the evaluation of i++ (left-hand side of +=) and
  • the value i before the evaluation of i++ (right-hand side of +=).

Solution 4 - C#

First, i++ returns 0. Then i is incremented by 1. Lastly i is set to the initial value of i which is 0 plus the value i++ returned, which is zero too. 0 + 0 = 0.

Solution 5 - C#

This is simply left to right, bottom-up evaluation of the abstract syntax tree. Conceptually, the expression's tree is walked from top down, but the evaluation unfolds as the recursion pops back up the tree from the bottom.

// source code
i += i++;

// abstract syntax tree

     +=
    /  \
   i    ++ (post)
         \
         i

Evaluation begins by considering the root node +=. That is the major constituent of the expression. The left operand of += must be evaluated to determine the place where we store the variable, and to obtain the prior value which is zero. Next, the right side must be evaluated.

The right side is a post-incrementing ++ operator. It has one operand, i which is evaluated both as a source of a value, and as a place where a value is to be stored. The operator evaluates i, finding 0, and consequently stores a 1 into that location. It returns the prior value, 0, in accordance with its semantics of returning the prior value.

Now control is back to the += operator. It now has all the info to complete its operation. It knows the place where to store the result (the storage location of i) as well as the prior value, and it has the value to added to the prior value, namely 0. So, i ends up with zero.

Like Java, C# has sanitized a very asinine aspect of the C language by fixing the order of evaluation. Left-to-right, bottom-up: the most obvious order that is likely to be expected by coders.

Solution 6 - C#

Because i++ first returns the value, then increments it. But after i is set to 1, you set it back to 0.

Solution 7 - C#

The post-increment method looks something like this

int ++(ref int i)
{
    int c = i;
    i = i + 1;
    return c;
}

So basically when you call i++, i is increment but the original value is returned in your case it's 0 being returned.

Solution 8 - C#

The post fix increment operator, ++, gives the variable a value in the expression and then do the increment you assigned returned zero (0) value to i again that overwrites the incremented one (1), so you are getting zero. You can read more about increment operator in ++ Operator (MSDN).

Solution 9 - C#

i++ means: return the value of i THEN increment it.

i += i++ means: Take the current value of i. Add the result of i++.

Now, let's add in i = 0 as a starting condition. i += i++ is now evaluated like this:

  1. What's the current value of i? It is 0. Store it so we can add the result of i++ to it.
  2. Evaluate i++ (evaluates to 0 because that's the current value of i)
  3. Load the stored value and add the result of step 2 to it. (add 0 to 0)

Note: At the end of step 2, the value of i is actually 1. However, in step 3, you discard it by loading the value of i before it was incremented.

As opposed to i++, ++i returns the incremented value.

Therefore, i+= ++i would give you 1.

Solution 10 - C#

Simple answer
int i = 0;
i += i++;
// Translates to:
i = i + 0; // because post increment returns the current value 0 of i
// Before the above operation is set, i will be incremented to 1
// Now i gets set after the increment,
// so the original returned value of i will be taken.
i = 0;

Solution 11 - C#

i += i++; will equal zero, because it does the ++ afterwards.

i += ++i; will do it before

Solution 12 - C#

The ++ postfix evaluates i before incrementing it, and += only evaluates i once.

Therefore, 0 + 0 = 0, as i is evaluated and used before it is incremented, as the postfix format of ++ is used. To get i incremented first, use the prefix form (++i).

(Also, just a note: you should only get 1, as 0 + (0 + 1) = 1)

References: http://msdn.microsoft.com/en-us/library/sa7629ew.aspx (+=)
http://msdn.microsoft.com/en-us/library/36x43w8w.aspx (++)

Solution 13 - C#

What C# is doing, and the "why" of the confusion

I also expected the value to be 1... but some exploration on that matter did clarify some points.

Cosider the following methods:

    static int SetSum(ref int a, int b) { return a += b; }

    static int Inc(ref int a) { return a++; }

I expected that i += i++ to be the same as SetSum(ref i, Inc(ref i)). The value of i after this statement is 1:

int i = 0;
SetSum(ref i, Inc(ref i));
Console.WriteLine(i); // i is 1

But then I came to another conclusion... i += i++ is actually the same as i = i + i++... so I have created another similar example, using these functions:

    static int Sum(int a, int b) { return a + b; }

    static int Set(ref int a, int b) { return a = b; }

After calling this Set(ref i, Sum(i, Inc(ref i))) the value of i is 0:

int i = 0;
Set(ref i, Sum(i, Inc(ref i)));
Console.WriteLine(i); // i is 0

This not only explains what C# is doing... but also why a lot of people got confused with it... including me.

Solution 14 - C#

A good mnemonic I always remember about this is the following:

If ++ stands after the expression, it returns the value it was before. So the following code

int a = 1;
int b = a++;

is 1, because a was 1 before it got increased by the ++ standing after a. People call this postfix notation. There is also a prefix notation, where things are exactly the opposite: if ++ stands before, the expression returns the value that it is after the operation:

int a = 1;
int b = ++a;

b is two in here.

So for your code, this means

int i = 0;
i += (i++);

i++ returns 0 (as described above), so 0 + 0 = 0.

i += (++i); // Here 'i' would become two

Scott Meyers describes the difference between those two notations in "Effective C++ programming". Internally, i++ (postfix) remembers the value i was, and calls the prefix-notation (++i) and returns the old value, i. This is why you should allways use ++i in for loops (although I think all modern compilers are translating i++ to ++i in for loops).

Solution 15 - C#

The only answer to your question which is correct is: Because it is undefined.

Ok, before you all burn me..

You all answered why i+=i++ is ok and logical to result in i=0.

I was tempted to down vote each and every 1 of your answers but the reputation hit I calculated would be too high..

Why I am so mad at you people? not because of what your answers explains..
I mean, every answer I read had made a remarkable effort to explain the impossible, I Applause!

But what is the result?? is it intuitive result - is it acceptable result??

Each one of you seen the "naked king" and somehow accepted it as a rational king.

You are all WRONG!

i+=i++; result in 0 is undefined.

a bug in the language evaluation mechanism if you will.. or even worse! a bug in design.

want a proof? of course you want!

int t=0; int i=0; t+=i++; //t=0; i=1

Now this... is intuitive result! because we first evaluated t assigned it with a value and only after evaluation and assignment we had the post operation happening - rational isn't it?

is it rational that: i=i++ and i=i yield the same result for i?

while t=i++ and t=i have different results for i.

The post operation is something that should happen after the statement evaluation.
Therefore:

int i=0;
i+=i++;

Should be the same if we wrote:

int i=0;
i = i + i ++;

and therefore the same as:

int i=0;
i= i + i;
i ++;

and therefore the same as:

int i=0;
i = i + i;
i = i + 1;

Any result which is not 1 indicate a bug in the complier or a bug in the language design if we go with rational thinking - however MSDN and many other sources tells us "hey - this is undefined!"

Now, before I continue, even this set of examples I gave is not supported or acknowledged by anyone.. However this is what according to intuitive and rational way should have been the result.

The coder should have no knowledge of how the assembly is being written or translated!

If it is written in a manner that will not respect the language definitions - it is a bug!

And to finish I copied this from Wikipedia, Increment and decrement operators :
Since the increment/decrement operator modifies its operand, use of such an operand more than once within the same expression can produce undefined results. For example, in expressions such as x − ++x, it is not clear in what sequence the subtraction and increment operators should be performed. Situations like this are made even worse when optimizations are applied by the compiler, which could result in the order of execution of the operations to be different than what the programmer intended.

And therefore.

The correct answer is that this SHOULD NOT BE USED! (as it is UNDEFINED!)

Yes.. - It has unpredictable results even if C# complier is trying to normalize it somehow.

I did not find any documentation of C# describing the behavior all of you documented as a normal or well defined behavior of the language. What I did find is the exact opposite!

[copied from MSDN documentation for Postfix Increment and Decrement Operators: ++ and --]

When a postfix operator is applied to a function argument, the value of the argument is not guaranteed to be incremented or decremented before it is passed to the function. See section 1.9.17 in the C++ standard for more information.

Notice those words not guaranteed...

Forgive me if that answer seems arrogant - I am not an arrogant person. I just consider that thousands of people come here to learn and the answers I read will mislead them and will harm their logic and understanding of the subject.

Solution 16 - C#

The ++ operator after the variable makes it a postfix increment. The incrementing happens after everything else in the statement, the adding and assignment. If instead, you put the ++ before the variable, it would happen before i's value was evaluated, and give you the expected answer.

Solution 17 - C#

The steps in calculation are:

  1. int i=0 //Initialized to 0
  2. i+=i++ //Equation
  3. i=i+i++ //after simplifying the equation by compiler
  4. i=0+i++ //i value substitution
  5. i=0+0 //i++ is 0 as explained below
  6. i=0 //Final result i=0

Here, initially the value of i is 0. WKT, i++ is nothing but: first use the i value and then increment the i value by 1. So it uses the i value, 0, while calculating i++ and then increments it by 1. So it results in a value of 0.

Solution 18 - C#

There are two options:

The first option: if the compiler read the statement as follows,

i++;
i+=i;

then the result is 2.

For

else if
i+=0;
i++;

the result is 1.

Solution 19 - C#

Be very careful: read the C FAQ: what you're trying to do (mixing assignement and ++ of the same variable) is not only unspecified, but it is also undefined (meaning that the compiler may do anything when evaluating!, not only giving "reasonnable" results).

Please read, section 3. The whole section is well worth a read! Especially 3.9, which explains the implication of unspecified. Section 3.3 gives you a quick summary of what you can, and cannot do, with "i++" and the like.

Depending on the compilers internals, you may get 0, or 2, or 1, or even anything else! And as it is undefined, it's OK for them to do so.

Solution 20 - C#

There's lot of excellent reasoning in above answers, I just did a small test and want to share with you

int i = 0;
i+ = i++;

Here result i is showing 0 result. Now consider below cases :

Case 1:

i = i++ + i; //Answer 1

earlier I thought above code resemble this so at first look answer is 1, and really answer of i for this one is 1.

Case 2:

i = i + i++; //Answer 0 this resembles the question code.

here increment operator doesn't come in execution path, unlike previous case where i++ has the chance to execute before addition.

I hope this helps a bit. Thanks

Solution 21 - C#

Hoping to answer this from a C programming 101 type of perspective.

Looks to me like it's happening in this order:

  1. i is evaluated as 0, resulting in i = 0 + 0 with the increment operation i++ "queued", but the assignment of 0 to i hasn't happened yet either.
  2. The increment i++ occurs
  3. The assignment i = 0 from above happens, effectively overwriting anything that #2 (the post-increment) would've done.

Now, #2 may never actually happen (probably doesn't?) because the compiler likely realizes it will serve no purpose, but this could be compiler dependent. Either way, other, more knowledgeable answers have shown that the result is correct and conforms to the C# standard, but it's not defined what happens here for C/C++.

How and why is beyond my expertise, but the fact that the previously evaluated right-hand-side assignment happens after the post-increment is probably what's confusing here.

Further, you would not expect the result to be 2 regardless unless you did ++i instead of i++ I believe.

Solution 22 - C#

Simply put,

i++, will add 1 to "i" after the "+=" operator has completed.

What you want is ++i, so that it will add 1 to "i" before the "+=" operator is executed.

Solution 23 - C#

i=0

i+=i

i=i+1

i=0;

Then the 1 is added to i.

i+=i++

So before adding 1 to i, i took the value of 0. Only if we add 1 before, i get the value 0.

i+=++i

i=2

Solution 24 - C#

The answer is i will be 1.

Let's have a look how:

Initially i=0;.

Then while calculating i +=i++; according to value of we will have something like 0 +=0++;, so according to operator precedence 0+=0 will perform first and the result will be 0.

Then the increment operator will applied as 0++, as 0+1 and the value of i will be 1.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionPeterView Question on Stackoverflow
Solution 1 - C#OdedView Answer on Stackoverflow
Solution 2 - C#Miguel AngeloView Answer on Stackoverflow
Solution 3 - C#dtbView Answer on Stackoverflow
Solution 4 - C#JongView Answer on Stackoverflow
Solution 5 - C#KazView Answer on Stackoverflow
Solution 6 - C#Yuriy FaktorovichView Answer on Stackoverflow
Solution 7 - C#Ash BurlaczenkoView Answer on Stackoverflow
Solution 8 - C#AdilView Answer on Stackoverflow
Solution 9 - C#CarlView Answer on Stackoverflow
Solution 10 - C#Praveen Kumar PurushothamanView Answer on Stackoverflow
Solution 11 - C#Wes CossickView Answer on Stackoverflow
Solution 12 - C#Nate KoppenhaverView Answer on Stackoverflow
Solution 13 - C#Miguel AngeloView Answer on Stackoverflow
Solution 14 - C#CarstenView Answer on Stackoverflow
Solution 15 - C#G.YView Answer on Stackoverflow
Solution 16 - C#KeithSView Answer on Stackoverflow
Solution 17 - C#Suresh MView Answer on Stackoverflow
Solution 18 - C#NEOView Answer on Stackoverflow
Solution 19 - C#Olivier DulacView Answer on Stackoverflow
Solution 20 - C#ThomasBeckerView Answer on Stackoverflow
Solution 21 - C#gkimseyView Answer on Stackoverflow
Solution 22 - C#seesharperView Answer on Stackoverflow
Solution 23 - C#learnwhatView Answer on Stackoverflow
Solution 24 - C#Shivam SharmaView Answer on Stackoverflow