I've seen them both being used in numerous pieces of C# code, and I'd like to know when to use i++ and when to use ++i?
(i being a number variable like int, float, double, etc).
The typical answer to this question, unfortunately posted here already, is that one does the increment "before" remaining operations and the other does the increment "after" remaining operations. Though that intuitively gets the idea across, that statement is on the face of it completely wrong. The sequence of events in time is extremely well-defined in C#, and it is emphatically not the case that the prefix (++var) and postfix (var++) versions of ++ do things in a different order with respect to other operations.
It is unsurprising that you'll see a lot of wrong answers to this question. A great many "teach yourself C#" books also get it wrong. Also, the way C# does it is different than how C does it. Many people reason as though C# and C are the same language; they are not. The design of the increment and decrement operators in C# in my opinion avoids the design flaws of these operators in C.
There are two questions that must be answered to determine what exactly the operation of prefix and postfix ++ are in C#. The first question is what is the result? and the second question is when does the side effect of the increment take place?
It is not obvious what the answer to either question is, but it is actually quite simple once you see it. Let me spell out for you precisely what x++ and ++x do for a variable x.
For the prefix form (++x):
x is evaluated to produce the variable
The value of the variable is copied to a temporary location
The temporary value is incremented to produce a new value (not overwriting the temporary!)
The new value is stored in the variable
The result of the operation is the new value (i.e. the incremented value of the temporary)
For the postfix form (x++):
x is evaluated to produce the variable
The value of the variable is copied to a temporary location
The temporary value is incremented to produce a new value (not overwriting the temporary!)
The new value is stored in the variable
The result of the operation is the value of the temporary
Some things to notice:
First, the order of events in time is exactly the same in both cases. Again, it is absolutely not the case that the order of events in time changes between prefix and postfix. It is entirely false to say that the evaluation happens before other evaluations or after other evaluations. The evaluations happen in exactly the same order in both cases as you can see by steps 1 through 4 being identical. The only difference is the last step - whether the result is the value of the temporary, or the new, incremented value.
You can easily demonstrate this with a simple C# console app:
public class Application
{
public static int currentValue = 0;
public static void Main()
{
Console.WriteLine("Test 1: ++x");
(++currentValue).TestMethod();
Console.WriteLine("\nTest 2: x++");
(currentValue++).TestMethod();
Console.WriteLine("\nTest 3: ++x");
(++currentValue).TestMethod();
Console.ReadKey();
}
}
public static class ExtensionMethods
{
public static void TestMethod(this int passedInValue)
{
Console.WriteLine($"Current:{Application.currentValue} Passed-in:{passedInValue}");
}
}
Here are the results...
Test 1: ++x
Current:1 Passed-in:1
Test 2: x++
Current:2 Passed-in:1
Test 3: ++x
Current:3 Passed-in:3
In the first test, you can see that both currentValue and what was passed into the TestMethod() extension show the same value, as expected.
However, in the second case, people will try to tell you that the increment of currentValue happens after the call to TestMethod(), but as you can see from the results, it happens before the call as indicated by the 'Current:2' result.
In this case, first the value of currentValue is stored in a temporary. Next, an incremented version of that value is stored back in currentValue but without touching the temporary which still stores the original value. Finally that temporary is passed to TestMethod(). If the increment happened after the call to TestMethod() then it would write out the same, non-incremented value twice, but it does not.
It's important to note that the value returned from both the currentValue++ and ++currentValue operations are based on the temporary and not the actual value stored in the variable at the time either operation exits.
Recall in the order of operations above, the first two steps copy the then-current value of the variable into the temporary. That is what's used to calculate the return value; in the case of the prefix version, it's that temporary value incremented while in the case of the suffix version, it's that value directly/non-incremented. The variable itself is not read again after the initial storage into the temporary.
Put more simply, the postfix version returns the value that was read from the variable (i.e. the value of the temporary) while the prefix version returns the value that was written back to the variable (i.e. the incremented value of the temporary). Neither return the variable's value.
This is important to understand because the variable itself could be volatile and have changed on another thread which means the return value of those operations could differ from the current value stored in the variable.
It is surprisingly common for people to get very confused about precedence, associativity, and the order in which side effects are executed, I suspect mostly because it is so confusing in C. C# has been carefully designed to be less confusing in all these regards. For some additional analysis of these issues, including me further demonstrating the falsity of the idea that prefix and postfix operations "move stuff around in time" see:
https://ericlippert.com/2009/08/10/precedence-vs-order-redux/
which led to this SO question:
int[] arr={0}; int value = arr[arr[0]++]; Value = 1?
You might also be interested in my previous articles on the subject:
https://ericlippert.com/2008/05/23/precedence-vs-associativity-vs-order/
and
https://ericlippert.com/2007/08/14/c-and-the-pit-of-despair/
and an interesting case where C makes it hard to reason about correctness:
https://learn.microsoft.com/archive/blogs/ericlippert/bad-recursion-revisited
Also, we run into similar subtle issues when considering other operations that have side effects, such as chained simple assignments:
https://learn.microsoft.com/archive/blogs/ericlippert/chaining-simple-assignments-is-not-so-simple
And here's an interesting post on why the increment operators result in values in C# rather than in variables:
Why can't I do ++i++ in C-like languages?
Oddly it looks like the other two answers don't spell it out, and it's definitely worth saying:
i++ means 'tell me the value of i, then increment'
++i means 'increment i, then tell me the value'
They are Pre-increment, post-increment operators. In both cases the variable is incremented, but if you were to take the value of both expressions in exactly the same cases, the result will differ.
If you have:
int i = 10;
int x = ++i;
then x will be 11.
But if you have:
int i = 10;
int x = i++;
then x will be 10.
Note as Eric points out, the increment occurs at the same time in both cases, but it's what value is given as the result that differs (thanks Eric!).
Generally, I like to use ++i unless there's a good reason not to. For example, when writing a loop, I like to use:
for (int i = 0; i < 10; ++i) {
}
Or, if I just need to increment a variable, I like to use:
++x;
Normally, one way or the other doesn't have much significance and comes down to coding style, but if you are using the operators inside other assignments (like in my original examples), it's important to be aware of potential side effects.
int i = 0;
Console.WriteLine(i++); // Prints 0. Then value of "i" becomes 1.
Console.WriteLine(--i); // Value of "i" becomes 0. Then prints 0.
Does this answer your question ?
The way the operator works is that it gets incremented at the same time, but if it is before a variable, the expression will evaluate with the incremented/decremented variable:
int x = 0; //x is 0
int y = ++x; //x is 1 and y is 1
If it is after the variable the current statement will get executed with the original variable, as if it had not yet been incremented/decremented:
int x = 0; //x is 0
int y = x++; //'y = x' is evaluated with x=0, but x is still incremented. So, x is 1, but y is 0
I agree with dcp in using pre-increment/decrement (++x) unless necessary. Really the only time I use the post-increment/decrement is in while loops or loops of that sort. These loops are the same:
while (x < 5) //evaluates conditional statement
{
//some code
++x; //increments x
}
or
while (x++ < 5) //evaluates conditional statement with x value before increment, and x is incremented
{
//some code
}
You can also do this while indexing arrays and such:
int i = 0;
int[] MyArray = new int[2];
MyArray[i++] = 1234; //sets array at index 0 to '1234' and i is incremented
MyArray[i] = 5678; //sets array at index 1 to '5678'
int temp = MyArray[--i]; //temp is 1234 (becasue of pre-decrement);
Etc, etc...
Just for the record, in C++, if you can use either (i.e.) you don't care about the ordering of operations (you just want to increment or decrement and use it later) the prefix operator is more efficient since it doesn't have to create a temporary copy of the object. Unfortunately, most people use posfix (var++) instead of prefix (++var), just because that is what we learned initially. (I was asked about this in an interview). Not sure if this is true in C#, but I assume it would be.
I think I'll try answering the question using code. Imagine the following methods for, say, int:
// The following are equivalent:
// ++i;
// PlusPlusInt(ref i);
//
// The argument "value" is passed as a reference,
// meaning we're not incrementing a copy.
static int PlusPlusInt(ref int value)
{
// Increment the value.
value = value + 1;
// Return the incremented value.
return value;
}
// The following are equivalent:
// i++;
// IntPlusPlus(ref i);
//
// The argument "value" is passed as a reference,
// meaning we're not incrementing a copy.
static int IntPlusPlus(ref int value)
{
// Keep the original value around before incrementing it.
int temp = value;
// Increment the value.
value = value + 1;
// Return what the value WAS.
return temp;
}
Assuming you know how ref works, this should clear this up really nicely. Explaining it in english is a lot more clunky in my opinion.
Related
Trying to control a variable in a script from another script in C# however when I reference it and try to get it to increase the value by one, I get the error of "The name i does not exist in current context."
Whole code unit would be
//Update enemy amount
GameObject theManager = GameObject.Find("EnemyManager");
AutomaticDifficultyManager managerScript = theManager.GetComponent<AutomaticDifficultyManager>();
AutomaticDifficultyManager.amountOfEnemies ++i;
This seems like such a simple fix yet for some reason it's not clicking why I can't get it to simply increase the variable by one count.
I assume you want to increase the value stored within amountOfEnemies?
The code for that would be ++managerScript.amountOfEnemies.
There is a difference between the ++ in front of a variable and after it. If you prepend the ++, essentially what happens is, the value gets increased first and is then used. If you postfix the ++, the value as is is used, and increased afterwards.
As an example:
int x = 0;
int newValue = ++x;
// newValue now has the value of 1 and x as well.
int nextTry = x++;
// nextTry is now still at 1 while x is at 2.
I recall reading somewhere that for a variable int i both ++i and i++ generate a temporary in C#. Does anyone know why that is the case? Is their performance identical?
UPDATE
So from Eric Lippert's answer in the duplicate, the steps for pre-increment are as follows:
For pre-increment
1) x is evaluated to produce the variable
2) the value of the variable is copied to a temporary location
3) the temporary value is incremented to produce a new value (not overwriting the temporary!)
4) the new value is stored in the variable
5) the result of the operation is the new value
Why is step 2 necessary? Why not increment the variable in place?
The answer is: they don't. Not in the sense implied by the title.
First please note: as per Eric's article (which, surprisingly, was criticised by many), the sequence of events that takes place in pre-increment and post-increment in C# is identical. Not just similar, but identical. The same things happen in the same order.
Second, there are no 'temporaries' as such. the 'temporary location' Eric is referring to is conceptual, but corresponds in practice to a machine register. A value is copied from memory to a register, the value is incremented, and the value is stored back into memory.
But there is another aspect. Unlike C/C++, C# guarantees the order of evaluation of expressions. In C# the following code is well-defined, where in C it is not.
j = ++i + i++;
But take something simpler:
j = ++i + f(i); // first
j = i++ + f(i); // second
In the first case the value of the variable is available for use in the subsequent expression, but in the second case it is not. Instead there is a conceptual temporary resulting from the first increment that is used in the following function call. An additional register may be used in the second case.
From this post (and not only) we got to the point that the ++ operator cannot be applied on expressions returning value.
And it's really obvious that 5++ is better to write as 5 + 1. I just want to summarize the whole thing around the increment/decrement operator. So let's go through these snippets of code that could be helpful to somebody stuck with the ++ first time at least.
// Literal
int x = 0++; // Error
// Constant
const int Y = 1;
double f = Y++; // error. makes sense, constants are not variables actually.
int z = AddFoo()++; // Error
Summary: ++ works for variables, properties (through a synthetic sugar) and indexers(the same).
Now the interest part - any literal expressions are optimized in CSC and, hence when we write, say
int g = 5 + 1; // This is compiled to 6 in IL as one could expect.
IL_0001: ldc.i4.6 // Pushes the integer value of 6 onto the evaluation stack as an int32.
For 5++ doesn't mean 5 becomes 6, it could be a shorthand for 5 + 1, like for x++ = x + 1
What's the real reason behind this restriction?
int p = Foo()++ //? yes you increase the return value of Foo() with 1, what's wrong with that?
Examples of code that can lead to logical issues are appreciated.
One of real-life example could be, perform one more actions than in the array.
for (int i = 0; i < GetCount()++; i++) { }
Maybe the lack of usage opts compiler teams to avoid similar features?
I don't insist this is a feature we lack of, just want to understand the dark side of this for compiler writers perhaps, though I'm not. But I know c++ allows this when returning a reference in the method. I'm neither a c++ guy(very poor knowledge) just want to get the real gist of the restriction.
Like, is it just because c# guys opted to restrict the ++ over value expressions or there are definite cases leading to unpredictable results?
In order for a feature to be worth supporting, it really needs to be useful. The code you've presented is in every case less readable than the alternative, which is just to use the normal binary addition operator. For example:
for (int i = 0; i < GetCount() + 1; i++) { }
I'm all in favour of the language team preventing you from writing unreadable code when in every case where you could do it, there's a simpler alternative.
Well before using these operators you should try to read up on how they do what they do. In particular you should understand the difference between postfix and prefix, which could help figure out what is and isn't allowed.
The ++ and -- operators modify their operands. Which means that the operand must be modifiable. If you can assign a value to the expression in question then it is modifiable, and is probably a variable(c#).
Taking a look at what these operators actually do. The postfix operators should increment after your line of code executes. As for the prefix operators, well they would need to have access to the value before the method had even been called yet. The way I read the syntax is ++lvalue (or ++variable) converting to memory operations:[read, write, read] or for lvalue++ [read, read, write] Though many compilers probably optimize secondary reads.
So looking at foo()++; the value is going to be plopped dead in the center of executing code. Which would mean the compiler would need to save the value somewhere more long-term in order for operations to be performed on said value, after the line of code has finished executing. Which is no doubt the exact reason C++ does not support this syntax either.
If you were to be returning a reference the compiler wouldn't have any trouble with the postfix. Of course in C# value types (ie. int, char, float, etc) cannot be passed by reference as they are value types.
I add an unexpected behaviour from C#/WPF
private void ButtonUp_Click(object sender, RoutedEventArgs e)
{
int quant;
if( int.TryParse(Qnt.Text, out quant))
{
string s = ((quant++).ToString());
Qnt.Text = s;
}
}
So, if I get quant as 1, quant will be incremented to 2. But the s string will be 1. Is this a question of precedence?
EDIT:
I re-wrote this as:
quant++;
Qnt.Text = quant.ToString();
and now this works as I expected.
You are using the post-increment operator. This evalutates to the original value, and then increments. To do what you want in a one-liner you can use the pre-increment operator instead.
(++quant).ToString();
But even better would be to avoid all such pitfalls and do it like this:
quant++;
string s = quant.ToString();
With the first version you have to think about the order in which things happen. In the second version no thought is required. Always value code clarity more highly than conciseness.
It's easy to believe that the one-line version is somehow faster, but that's not true. It might have been true back in the day in 1970s C systems, but even then that I doubt.
The problem is that you're using a post-increment instead of a pre-increment... but why would you want to write this convoluted code? Just separate out the side-effect (incrementing) and the ToString call:
if (int.TryParse(Qnt.Text, out quant))
{
quant++;
Qnt.Text = quant.ToString();
}
Or even forego the actual increment given that you're not going to read the value again:
if (int.TryParse(Qnt.Text, out quant))
{
Qnt.Text = (quant + 1).ToString();
}
Where possible, avoid using compound assignment in the middle of other expressions. It generally leads to pain.
Additionally, it feels like all this parsing and formatting is hiding the real model, which is that there should be an int property somewhere, which might be reflected in the UI. For example:
private void ButtonUp_Click(object sender, RoutedEventArgs e)
{
// This is an int property
Quantity++;
// Now reflect the change in the UI. Ideally, do this through binding
// instead.
Qnt.Text = Quantity.ToString();
}
Now I'll do something that shouldn't be done... I'll try to simplify what Eric Lippert wrote here What is the difference between i++ and ++i? I hope I'm not writing anything too much wrong :-)
Now... What does the pre-increment and post-increment operators do? Simplifying and ignoring all the copy that are done in-between (and remembering that they aren't atomic operators in multi-threaded environments):
both of them are expressions (like i + 1) that return a result (like i + 1) but that have a side-effect (unlike i + 1). The side-effect is that they increment the variable i. The big question is "in which order everything happens?" The answer is quite simple:
pre increment ++i: increments i and returns the new value of i
post increment i++: increments i and returns the old value of i
Now... The important part is that the increments i always happens first. Then a value (the old or the new) is returned.
Let's make an example (the example of Lippert is quite complex. I'll make a different, more simple example, that isn't as much complete but that is enough to check if the order I said before is right or not) (technically I'll make two examples)
Example 1:
unchecked
{
int i = Int32.MaxValue;
Console.WriteLine("Hello! I'm trying to do my work here {0}", i++);
Console.WriteLine("Work done {1}", i);
}
Example 2:
checked
{
int i = Int32.MaxValue;
Console.WriteLine("Hello! I'm trying to do my work here {0}", i++);
Console.WriteLine("Work done {1}", i);
}
checked means that if there is an overflow an exception (OverflowException) will be thrown. unchecked means that the same operation won't throw an exception. Int32.MaxValue + 1 surely will overflow. With checked there will be an exception, with unchecked i will become -1.
Let's try running the first code piece. Result:
Hello! I'm trying to do my work here 2147483647
Work done -1
Ok... The i was incremented but the Console.WriteLine received the old value (Int32.MaxValue == 2147483647). From this example we can't determine the order of the post-increment and of the calling of Console.WriteLine.
Let's try running the second code piece. Result:
System.OverflowException: Arithmetic operation resulted in an overflow.
Ok... It's quite clear that first the post-increment was executed, caused an exception, and then clearly the Console.WriteLine wasn't executed (because the program ended).
So we know that the order I said is the right one.
Now. What should you learn from this example? The same thing I learned many years ago. Pre and post increments in C and C# are good for obfuscated code contests. They aren't good for many other things (but note that C++ is different!). From that lesson I learned that there are exactly two places where you can use post-increment freely, and there are exactly zero places where you can use pre-increment freely.
"Safe" post-increment
for (int i = 0; i < x; i++)
and
i++; // Written alone. Nothing else on the same line but a comment if necessary.
"Safe" pre-increment
(nothing)
In this case, first quant.ToString() will be called and then quant will be incremented.
If you write ((++quant).ToString()) the first step will be incrementing quant and then quant.ToString() will be called.
string s = ((quant++).ToString());
can be distributed as
use quant for toString() method call before incrementing, and then
execute assignment operator, and then
increment `quant'
try with ++quant.
I've seen them both being used in numerous pieces of C# code, and I'd like to know when to use i++ and when to use ++i?
(i being a number variable like int, float, double, etc).
The typical answer to this question, unfortunately posted here already, is that one does the increment "before" remaining operations and the other does the increment "after" remaining operations. Though that intuitively gets the idea across, that statement is on the face of it completely wrong. The sequence of events in time is extremely well-defined in C#, and it is emphatically not the case that the prefix (++var) and postfix (var++) versions of ++ do things in a different order with respect to other operations.
It is unsurprising that you'll see a lot of wrong answers to this question. A great many "teach yourself C#" books also get it wrong. Also, the way C# does it is different than how C does it. Many people reason as though C# and C are the same language; they are not. The design of the increment and decrement operators in C# in my opinion avoids the design flaws of these operators in C.
There are two questions that must be answered to determine what exactly the operation of prefix and postfix ++ are in C#. The first question is what is the result? and the second question is when does the side effect of the increment take place?
It is not obvious what the answer to either question is, but it is actually quite simple once you see it. Let me spell out for you precisely what x++ and ++x do for a variable x.
For the prefix form (++x):
x is evaluated to produce the variable
The value of the variable is copied to a temporary location
The temporary value is incremented to produce a new value (not overwriting the temporary!)
The new value is stored in the variable
The result of the operation is the new value (i.e. the incremented value of the temporary)
For the postfix form (x++):
x is evaluated to produce the variable
The value of the variable is copied to a temporary location
The temporary value is incremented to produce a new value (not overwriting the temporary!)
The new value is stored in the variable
The result of the operation is the value of the temporary
Some things to notice:
First, the order of events in time is exactly the same in both cases. Again, it is absolutely not the case that the order of events in time changes between prefix and postfix. It is entirely false to say that the evaluation happens before other evaluations or after other evaluations. The evaluations happen in exactly the same order in both cases as you can see by steps 1 through 4 being identical. The only difference is the last step - whether the result is the value of the temporary, or the new, incremented value.
You can easily demonstrate this with a simple C# console app:
public class Application
{
public static int currentValue = 0;
public static void Main()
{
Console.WriteLine("Test 1: ++x");
(++currentValue).TestMethod();
Console.WriteLine("\nTest 2: x++");
(currentValue++).TestMethod();
Console.WriteLine("\nTest 3: ++x");
(++currentValue).TestMethod();
Console.ReadKey();
}
}
public static class ExtensionMethods
{
public static void TestMethod(this int passedInValue)
{
Console.WriteLine($"Current:{Application.currentValue} Passed-in:{passedInValue}");
}
}
Here are the results...
Test 1: ++x
Current:1 Passed-in:1
Test 2: x++
Current:2 Passed-in:1
Test 3: ++x
Current:3 Passed-in:3
In the first test, you can see that both currentValue and what was passed into the TestMethod() extension show the same value, as expected.
However, in the second case, people will try to tell you that the increment of currentValue happens after the call to TestMethod(), but as you can see from the results, it happens before the call as indicated by the 'Current:2' result.
In this case, first the value of currentValue is stored in a temporary. Next, an incremented version of that value is stored back in currentValue but without touching the temporary which still stores the original value. Finally that temporary is passed to TestMethod(). If the increment happened after the call to TestMethod() then it would write out the same, non-incremented value twice, but it does not.
It's important to note that the value returned from both the currentValue++ and ++currentValue operations are based on the temporary and not the actual value stored in the variable at the time either operation exits.
Recall in the order of operations above, the first two steps copy the then-current value of the variable into the temporary. That is what's used to calculate the return value; in the case of the prefix version, it's that temporary value incremented while in the case of the suffix version, it's that value directly/non-incremented. The variable itself is not read again after the initial storage into the temporary.
Put more simply, the postfix version returns the value that was read from the variable (i.e. the value of the temporary) while the prefix version returns the value that was written back to the variable (i.e. the incremented value of the temporary). Neither return the variable's value.
This is important to understand because the variable itself could be volatile and have changed on another thread which means the return value of those operations could differ from the current value stored in the variable.
It is surprisingly common for people to get very confused about precedence, associativity, and the order in which side effects are executed, I suspect mostly because it is so confusing in C. C# has been carefully designed to be less confusing in all these regards. For some additional analysis of these issues, including me further demonstrating the falsity of the idea that prefix and postfix operations "move stuff around in time" see:
https://ericlippert.com/2009/08/10/precedence-vs-order-redux/
which led to this SO question:
int[] arr={0}; int value = arr[arr[0]++]; Value = 1?
You might also be interested in my previous articles on the subject:
https://ericlippert.com/2008/05/23/precedence-vs-associativity-vs-order/
and
https://ericlippert.com/2007/08/14/c-and-the-pit-of-despair/
and an interesting case where C makes it hard to reason about correctness:
https://learn.microsoft.com/archive/blogs/ericlippert/bad-recursion-revisited
Also, we run into similar subtle issues when considering other operations that have side effects, such as chained simple assignments:
https://learn.microsoft.com/archive/blogs/ericlippert/chaining-simple-assignments-is-not-so-simple
And here's an interesting post on why the increment operators result in values in C# rather than in variables:
Why can't I do ++i++ in C-like languages?
Oddly it looks like the other two answers don't spell it out, and it's definitely worth saying:
i++ means 'tell me the value of i, then increment'
++i means 'increment i, then tell me the value'
They are Pre-increment, post-increment operators. In both cases the variable is incremented, but if you were to take the value of both expressions in exactly the same cases, the result will differ.
If you have:
int i = 10;
int x = ++i;
then x will be 11.
But if you have:
int i = 10;
int x = i++;
then x will be 10.
Note as Eric points out, the increment occurs at the same time in both cases, but it's what value is given as the result that differs (thanks Eric!).
Generally, I like to use ++i unless there's a good reason not to. For example, when writing a loop, I like to use:
for (int i = 0; i < 10; ++i) {
}
Or, if I just need to increment a variable, I like to use:
++x;
Normally, one way or the other doesn't have much significance and comes down to coding style, but if you are using the operators inside other assignments (like in my original examples), it's important to be aware of potential side effects.
int i = 0;
Console.WriteLine(i++); // Prints 0. Then value of "i" becomes 1.
Console.WriteLine(--i); // Value of "i" becomes 0. Then prints 0.
Does this answer your question ?
The way the operator works is that it gets incremented at the same time, but if it is before a variable, the expression will evaluate with the incremented/decremented variable:
int x = 0; //x is 0
int y = ++x; //x is 1 and y is 1
If it is after the variable the current statement will get executed with the original variable, as if it had not yet been incremented/decremented:
int x = 0; //x is 0
int y = x++; //'y = x' is evaluated with x=0, but x is still incremented. So, x is 1, but y is 0
I agree with dcp in using pre-increment/decrement (++x) unless necessary. Really the only time I use the post-increment/decrement is in while loops or loops of that sort. These loops are the same:
while (x < 5) //evaluates conditional statement
{
//some code
++x; //increments x
}
or
while (x++ < 5) //evaluates conditional statement with x value before increment, and x is incremented
{
//some code
}
You can also do this while indexing arrays and such:
int i = 0;
int[] MyArray = new int[2];
MyArray[i++] = 1234; //sets array at index 0 to '1234' and i is incremented
MyArray[i] = 5678; //sets array at index 1 to '5678'
int temp = MyArray[--i]; //temp is 1234 (becasue of pre-decrement);
Etc, etc...
Just for the record, in C++, if you can use either (i.e.) you don't care about the ordering of operations (you just want to increment or decrement and use it later) the prefix operator is more efficient since it doesn't have to create a temporary copy of the object. Unfortunately, most people use posfix (var++) instead of prefix (++var), just because that is what we learned initially. (I was asked about this in an interview). Not sure if this is true in C#, but I assume it would be.
I think I'll try answering the question using code. Imagine the following methods for, say, int:
// The following are equivalent:
// ++i;
// PlusPlusInt(ref i);
//
// The argument "value" is passed as a reference,
// meaning we're not incrementing a copy.
static int PlusPlusInt(ref int value)
{
// Increment the value.
value = value + 1;
// Return the incremented value.
return value;
}
// The following are equivalent:
// i++;
// IntPlusPlus(ref i);
//
// The argument "value" is passed as a reference,
// meaning we're not incrementing a copy.
static int IntPlusPlus(ref int value)
{
// Keep the original value around before incrementing it.
int temp = value;
// Increment the value.
value = value + 1;
// Return what the value WAS.
return temp;
}
Assuming you know how ref works, this should clear this up really nicely. Explaining it in english is a lot more clunky in my opinion.