c# Post-incrementing problem

P

Patrick Wood

I found a problem with C# and post increments. I was going
through some source code in c++ and found someone did a
post increment:

int x=0;
for(int i=0; i<10; i++)
{
x = x++;
}

In c++, you'd get 0,1,...,9 (as expected). This doesn't
work in C#. In C#, you get 0,...,0. It seems the post
increment is ignored in this case. However, the lines:
x=4;
y=x++;
produces y=4, x=5 (as expected)

Should c# be behaving this way or is there a compiler
error? After looking at the assembly code in c++ and c#, it
looks like a bug in c#.
 
A

Alex

I found a problem with C# and post increments. I was going
through some source code in c++ and found someone did a
post increment:

int x=0;
for(int i=0; i<10; i++)
{
x = x++;
}

I tried this code and confirmed it doesn't increment x. Must be a bug.
 
A

Alex

I found a problem with C# and post increments. I was going
through some source code in c++ and found someone did a
post increment:

int x=0;
for(int i=0; i<10; i++)
{
x = x++;
}

However, post decrement, preincrment, and predecrement work inside the loop.
Only postincrement fails.
 
J

Jasper Kent

Fascinating.

I have to say, the C++ behaviour (which is certainly what happens) is
*not* what I would expect. The C# seems correct.

x++ should increment the value of x but return the old value. Thus on
the first time through the loop, x++ increments x to 1, but returns the
old value of 0. The assignment of this 0 into x should occur *after* the
++, and so x should stay at zero, as it does in C#.

Suppose we declare y as another int.

Replacing the loop body with:

y = x++;
x = y;

gives the behaviour of x staying at 0, because the assigment definitely
occurs after the increment.

Now here's wierd:

x = y = x++;

First time through the loop, y gets 0 and x get 1. I suspect that
there's an optimisation occuring that is making the C++ behaviour wrong.

Regards,

Jasper Kent
 
W

William Ryan

If you use the x = x++ then I get 0's as well...however if you just use x++
all works correctly so you can get whatever you need done.
 
B

Bruno Jouhier [MVP]

I've already seen similar problems reported on this newsgroup. It boiled
down to a difference between the C# specs and the C++ specs. So, you should
read the language specs in detail, it is probably not a bug.

My 2 cents on this one: the compiler should rather issue at least a warning
on "dangerous" constructs like this one. It should flag code that may have
ambiguous interpretation and it should discourage people from writing it.

Bruno.
 
P

Patrick Wood

I agree with c++/c# producing all 0's with the loop body
you gave because the two statements are not
exactly equivalent.

Take:

x = x++;

Regardless of the order of operations, x will be post
incremented at some time. So, if you post increment before
you do the assignment or after the assignment, you will
still get an incremented x. So, the c++ is right. I don't
see how (regardless of the spec) x could NOT be
incremented in this context.
 
J

Joe

Patrick Wood said:
I found a problem with C# and post increments. I was going
through some source code in c++ and found someone did a
post increment:

int x=0;
for(int i=0; i<10; i++)
{
x = x++;
}

In c++, you'd get 0,1,...,9 (as expected). This doesn't
work in C#. In C#, you get 0,...,0. It seems the post
increment is ignored in this case. However, the lines:
x=4;
y=x++;
produces y=4, x=5 (as expected)

Should c# be behaving this way or is there a compiler
error? After looking at the assembly code in c++ and c#, it
looks like a bug in c#.

Hi Patrick,

Given:

.locals init ([0] int32 x,
[1] int32 i)

IL_0006: ldloc.0 // push x on the stack - 0
IL_0007: dup // copy top of stack - 0, 0
IL_0008: ldc.i4.1 // push 1 on the stack - 1, 0, 0
IL_0009: add // add 1 and 0 - 1, 0
IL_000a: stloc.0 // pop x from the stack - 0 : x=1
IL_000b: stloc.0 // pop x from the stack - : x=0

At first glance, it seems that IL_000a should have went before IL_0008, but
really it should be looked at in more depth than just the casual look I've
given it.

Instead, it just stores1 into x and then stores 0 into x, which wipes out
the post-increment. Sure looks like a bug.

The second case worked because you assigned the value to y and not x, which
is okay.

Joe
 
M

Michael Mayer

Alex said:
On [GMT+0100=CET],
Patrick Wood <[email protected]> thought hard and spewed:

However, post decrement, preincrment, and predecrement work inside the loop.
Only postincrement fails.

Not true. Pose decrement works the same as post increment, as I would
expect.

public static void Main ()
{
Console.WriteLine ("Testing x=x++;");
int x = 100;
for(int i=0; i < 5; i++)
{
x = x++;
Console.Write (x + " ");
}
Console.WriteLine (" x = " + x);

Console.WriteLine ("Testing y=y--;");
int y = 100;
for(int i=0; i < 5; i++)
{
y = y--;
Console.Write (y + " ");
}
Console.WriteLine (" y = " + y);

Console.ReadLine();
}

RESULTS

Testing x=x++;
100 100 100 100 100 x = 100
Testing y=y--;
100 100 100 100 100 y = 100
 
J

Jasper Kent

Sure x++ causes x to get incremented at some time, but the postfix
operator returns the *old* value of x (remember the joke that C++ should
be called ++C, because C++ returns the old value?).

Thus it is the old value (0) that is assigned into x, and hence if this
assignment is done after the ++ (as it seems it sould be) then x, having
gone up to 1, returns to 0.

The behaviour of:

x = y = x++;

giving different values of x and y seems to make it pretty obvious
(whatever the actual values) that something is wrong.

Jasper Kent
 
D

David Olsen

Patrick said:
I found a problem with C# and post increments. I was going
through some source code in c++ and found someone did a
post increment:

int x=0;
for(int i=0; i<10; i++)
{
x = x++;
}

In c++, you'd get 0,1,...,9 (as expected).

In C++, the behavior of this code is undefined. 'x' is modified twice
between sequence points (once by ++, once by =), so the C++ standard
makes no guarantees about the code's behavior. You can't expect the
code to do anything in particular.
 
J

Joe Mayo

Patrick Wood said:
I found a problem with C# and post increments. I was going
through some source code in c++ and found someone did a
post increment:

int x=0;
for(int i=0; i<10; i++)
{
x = x++;
}

In c++, you'd get 0,1,...,9 (as expected). This doesn't
work in C#. In C#, you get 0,...,0. It seems the post
increment is ignored in this case. However, the lines:
x=4;
y=x++;
produces y=4, x=5 (as expected)

Should c# be behaving this way or is there a compiler
error? After looking at the assembly code in c++ and c#, it
looks like a bug in c#.

I'll retract my previous thoughts on this because the specs appear to
describe this behavior as correct:

14.5.9 Postfix increment and decrement operators

.. 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.

Here's my interpretation of what this says:

using System;

class PostIncrementTest
{
static void Main()
{
int x = 0;

// * x is evaluated to produce the variable.
// * The value of x is saved.
int savedX = x;

// * 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.
x = savedX + 1;

// * The saved value of x becomes the result
// of the operation.
x = savedX;

Console.WriteLine("x = {0}", x);

//
// However, when y is used you get this
//

x = 0;
int y = 0;

// * x is evaluated to produce the variable.
// * The value of x is saved.
savedX = x;

// * 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.
y = savedX + 1;

// * The saved value of x becomes the result
// of the operation.
x = savedX;

Console.WriteLine("x = {0}, y = {1}", x, y);

Console.ReadLine();

}
}

And the output:

x = 0
x = 0, y = 1

To be sure, I'd be interested in seeing if someone from MS could clarify.

Joe
 
M

mikeb

Patrick said:
I found a problem with C# and post increments. I was going
through some source code in c++ and found someone did a
post increment:

int x=0;
for(int i=0; i<10; i++)
{
x = x++;
}

In c++, you'd get 0,1,...,9 (as expected). This doesn't
work in C#. In C#, you get 0,...,0. It seems the post
increment is ignored in this case. However, the lines:
x=4;
y=x++;
produces y=4, x=5 (as expected)

Should c# be behaving this way or is there a compiler
error? After looking at the assembly code in c++ and c#, it
looks like a bug in c#.

Actually, you are relying on undefined behavior in the C++ sample. Look
at the C Language FAQ, items 3.1 to 3.4:

http://www.eskimo.com/~scs/C-faq/s3.html

My reading of the C# Language Specification (section 7.2.1 Operator
precedence and associativity) indicates that the "x = x++" expression is
well-defined, and will result in x remaining the same after the entire
expression is complete.
 
A

Austin Ehlers

According to the C# language specification, in 14.5.9 Paragraph 5,
line 2, states:

"The result of x++ or x--is the value of x before the operation,
whereas the result of ++x or --x is the value of x after the
operation."

You can check this out yourself:

int x=0;
MessageBox.Show(x++.ToString()); //shows "0"

And the reason "x=x++;" doesn't do anything is because assignment
occurs before increment (hence post-*), and the *value* of x is
increased, but is not stored (as assignment has already occured).

Austin Ehlers
 
P

Pat

Yes, I agree that for the x++ portion, x will take on the
value of x before the statement (ie. x=0), but my
understanding was that x++ has an implicit assignment. In
other words, I thought x++ is equivalent to x=x+1

Regardless, it seems wrong to me, but may be right
according to the c# spec.
 
J

Jon Skeet

Pat said:
Yes, I agree that for the x++ portion, x will take on the
value of x before the statement (ie. x=0), but my
understanding was that x++ has an implicit assignment.

x++ has an implicit assignment to x, yes. However, that's effectively
overridden by the later assignment to x.
In other words, I thought x++ is equivalent to x=x+1

Yes, it is - but the value of the expression is the *original* value,
and that's what then gets assigned by the "x=" part of x=x++;
Regardless, it seems wrong to me, but may be right
according to the c# spec.

Basically remember that the increment happens immediately the
expression is evaluated, *not* after the whole statement is evaluated.
 
J

Jack Hanebach

Pat said:
Yes, I agree that for the x++ portion, x will take on the
value of x before the statement (ie. x=0), but my
understanding was that x++ has an implicit assignment. In
other words, I thought x++ is equivalent to x=x+1

Regardless, it seems wrong to me, but may be right
according to the c# spec.

Look at it this way:

x = x++; is equivalent to x = x.operator++();

where int.operator++() translates to something like

{
int temp = this;
this = this + 1;
return temp;
}

Now the behaviour you see makes sense, doesn't it.
 
S

Stu Smith

This is the crucial point, and one I was just about to make.

People assume if their C++ compiler does something, then every other C++
compiler should do the same.

I'm not sure why you'd want to do this in C# anyway, it's absolutely
horrible code.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top