What Does I++ Really Mean?
The Question Has Been Asked Many Times, "What's the Difference Between I++ and ++I". the Accepted Answer at What Is the Difference Between I++ and ++I? , and...
The question has been asked many times, "What's the difference between i++ and ++i". The accepted answer at What is the difference between i++ and ++i?, and I've seen this language in many other places as well, is that, "i++ means 'tell me the value of i, then increment', whereas ++i means 'increment i, then tell me the value'.
What confuses me is that I was not aware that we were discussing getting back a value for i in either scenario. I thought that i++ is syntactically equivalent to:
i = i + 1;
which is a statement, not an expression, so I don't understand where i is being returned at all.
Can you please expain what the statement actually means?
Thanks,
For reasons unknown to me, this old question with an accepted answer is attracting new answers today, many of which contain significant errors or omissions. Let me attempt to answer the question as asked definitively.
The question has been asked many times, "What's the difference between i++ and ++i". The accepted answer at [...], and I've seen this language in many other places as well, is that, "i++ means 'tell me the value of i, then increment', whereas ++i means 'increment i, then tell me the value'.
As I noted in my answer to that same question: this characterization is common and a reasonable first cut at understanding but unfortunately misleading when you look at the semantics more carefully. Please do not be misled by this vague and not entirely accurate characterization. Read my answer to that question instead.
What confuses me is that I was not aware that we were discussing getting back a value for i in either scenario. I thought that
i++is syntactically equivalent toi = i + 1;which is a statement, not an expression, so I don't understand where i is being returned at all.
You have a number of misunderstandings here. Rather than attack them all, let's just say what the truth is.
First, ++i and i++ are not syntactically exactly equivalent to anything. You cannot necessarily take a legal program that contains an ++i or an i++ and transform it solely syntactically into another legal program. So just banish that thought from your head. These are morally equivalent to increment-and-assign, and ought to be semantically equivalent, but there is not necessarily a syntactic desugaring that preserves program semantics or legality.
Let us now say some more true things. But first, some caveats. For the purposes of this discussion, the incremented expression i is a variable of type int, which can be evaluated either as a variable or a value without side effects, including exceptions. Moreover, we suppose that the incrementing operation does not produce an exception. And moreover we presume a single thread of execution. If you wish to know the semantics of increments and assignments in cases where evaluating the variable can throw, or produce another side effect, or is not a variable but rather is a property, or the operations are user-defined, or multiple threads are observing or mutating the variable, see the specification for details.
That said, here are some true facts:
++i,i++, andi = i + 1are expressions++i;,i++;andi = i + 1;are statementsThe semantics of
++iare as follows:- temp1 is given the value of i
- temp2 is given the value of temp1 + 1
- i is given the value of temp2
- the value of the expression is temp2
The semantics of
i++are as follows:- temp1 is given the value of i
- temp2 is given the value of temp1 + 1
- i is given the value of temp2
- the value of the expression is temp1
Notice that the difference between the two forms is only what the value produced is. The steps that are taken to produce the side effect are identical in both cases. You are guaranteed in single-threaded C# that the side effect is observed complete before the value is produced.
- The semantics of
i = i + 1are as follows:- temp1 is given the value of i
- temp2 is given the value of temp1 + 1
- i is given the value of temp2
- the value of the expression is temp2
- Notice that the semantics of
i = i + 1are identical to the semantics of++i. This is not a guarantee that you can syntactically substitutei = i + 1for++ior vice versa, in an arbitrary program. In certain programs, this might be possible. Notice that the semantics of
i++does not admit an "easy" semantically equivalent form.((Func<int, int, int>)((int j, int k)=>j))(i, i=i+1)has the same semantics but is obviously a crazy thing to type.The semantics of the statement forms of all three are:
- Evaluate the expression as normal.
- Discard the result.
Hopefully this definitively clears up any misunderstandings about what is an expression, what is a statement, what side effects and values are produced by the expressions, and in what order do they happen. Again, note that this explanation is narrowly targeted at simple cases involving integer variables without side effects on a single thread. For the details of how these operations work on other types, or interact with exceptions, or how they work in multithreaded programs, consult the C# specification or ask a more specific question.
Finally: I personally still find all this confusing, and I've been programming in C descendant languages for 30 years and I implemented these semantics in C#. If I find them confusing, and if almost every answer to every question I see on these operators contains significant errors or omissions, then we can safely conclude that these are confusing operators. As a result, I almost never use ++ or -- in my production code. I think it is bad style to have an expression that is useful for both its value and its side effects.
Try to find a way to structure your program so that ever statement has one side effect, and side-effecting expressions are limited to expression statements. Avoid ++, and particularly avoid any scenario where i++ and ++i would have different semantics, because that's a point where the program is going to be harder to understand and therefore harder to maintain correctly.
Edit: See Eric's answer, mine is meh.
You are right. The ++ is equivalent to i = i + 1, but the point to remember is that i = i + 1 is not only a statement, but can also be used as an expression:
Console.WriteLine((i = i + 1) * 42); // will inc i, and then print i*42
Console.WriteLine(++i * 42); // exactly same
Console.WriteLine(i++ * 42); // will inc i, and print old_i*42
Console.WriteLine((i++) * 42); // exactly same
So to conclude simply:
// this
int j = ++i * 42;
// behaves like
int j = (i = i + 1) * 42;
// but this
int j = i++ * 42;
// actually behaves like
int prev = i;
i = i + 1;
int j = prev * 42;
I think you may consider the following two functions to get an analogy to the i++ and ++i.
public static int IPlusPlus(ref int i) {
// simply increment i before returning it
i = i + 1;
return i;
}
public static int PlusPlusI(ref int i) {
// increment i only after you already returned it
try {
return i;
}
finally {
i = i + 1;
}
}
Just like function calls, i++ and ++i are right-hand-side expressions, meaning var a = i++; and var a = ++i; are valid statements. But i++ = 5; and ++i = 5; are not valid as that would use them as left-hand-side expressions.