4

Can someone explain how the following code works?

static int index = 0;
public static int GetNextIndex()
{
    return index++;
}

I assumed that, as the increment operation happens after the return statement, the variable 'index' will never get incremented.

But when tested with C# compiler, I observed that 'index' is getting incremented.

How does a standard compiler handle this scenario?

Arctic
  • 807
  • 10
  • 22
  • 6
    What makes you think the increment happens after the return statement? The increment happens after the value of index has been obtained, *for use* in the return statement... – Damien_The_Unbeliever Oct 01 '13 at 14:08
  • Because it is postfix operator. – Arctic Oct 01 '13 at 14:15
  • 3
    @Fadi Read this answer by Eric Lippert explaining the mechanics of pre/postfix http://stackoverflow.com/a/3346729/860585 – Rotem Oct 01 '13 at 14:16
  • I tested by calling the function. And during the initial call the output was 0. That makes me think that, increment operation happens after the return statement. – Arctic Oct 01 '13 at 14:16
  • Take a look at the link provided by @Rotem (few seconds faster ^^). That's a *very* in depth answer on how *exactly* prefix/postfix version of `++` works. – Corak Oct 01 '13 at 14:18

2 Answers2

6
static int index = 0;
public static int GetNextIndex()
{
    return index++;
}

is equivalent to:

static int index = 0;
public static int GetNextIndex()
{
    int i = index;
    index = index + 1;
    return i;
}

hence index is incremented.

Ahmed KRAIEM
  • 10,267
  • 4
  • 30
  • 33
  • well, it's mostly equivalent. Technically the first code snippet only evaluates the expression `index` *once* throughout the method; you evaluate it three times, but it's pretty close. – Servy Oct 01 '13 at 14:21
  • If index wasn't an **int field** this wouldn't be equivalent. Evaluating an `int` field has no side effects. – Ahmed KRAIEM Oct 01 '13 at 14:26
  • It makes it a non-issue for one of the three cases, namely the case where it is being assigned to, as it has no side effects. However, you're reading the value of `index` twice, and it's possible for it to have changed (from manipulation in another thread) between those two reads. The first code snippet doesn't read from it twice, so it wouldn't observe such a change. And of course in the event that evaluating the expression caused side effects, it makes the whole thing that much more different. – Servy Oct 01 '13 at 14:28
  • That's wrong, even ++ is not "threadsafe". http://stackoverflow.com/a/4628660/393487 – Ahmed KRAIEM Oct 01 '13 at 14:33
  • 1
    "thread safe" isn't a descriptive term. Perhaps you meant to say that it's not atomic, which is true, and much more precise. I didn't say that it *was* atomic. I said that the variable is only read from once when the operator is executed. However, because it is both read from and written to, the entire operation is not atomic. That doesn't change the fact that this code reads from it twice while the operator reads from it once. Neither are atomic, but they aren't the same either. – Servy Oct 01 '13 at 14:38
  • 1
    Shouldn't the second line be `index = i + 1`? I think that would rectify the issue @Servy brings up. – Rotem Oct 01 '13 at 14:39
6

This is the intermediate language (IL) that the compiler generates (VS2013RC/.NET 4.5.1RC):

.method public hidebysig static int32 GetNextIndex() cil managed
{
    .maxstack 8
    L_0000: ldsfld int32 ConsoleApplication4.Program::index
    L_0005: dup 
    L_0006: ldc.i4.1 
    L_0007: add 
    L_0008: stsfld int32 ConsoleApplication4.Program::index
    L_000d: ret 
}

So, what does that do? Let's say that index has the value 6 before calling it.

    L_0000: ldsfld int32 ConsoleApplication4.Program::index

loads the value of index onto the evaluation stack - stack contains 6.

    L_0005: dup

duplicates the value on the top of the stack - stack contains 6, 6

    L_0006: ldc.i4.1

loads the value 1 onto the stack - stack contains 6, 6, 1

    L_0007: add 

adds the top two values on the stack, and places the result back on the stack. stack contains 6, 7

    L_0008: stsfld int32 ConsoleApplication4.Program::index

Stores the top value on the stack into index. index now equals 7, stack contains 6.

    L_000d: ret 

Takes the top value on the stack (6) as the return value.

Damien_The_Unbeliever
  • 234,701
  • 27
  • 340
  • 448