4

Possible Duplicate:
C#: Order of function evaluation (vs C)

Code snippet:

i += ++i;
a[++i] = i;
int result =  fun() - gun();
//statement of similar kind

Are their behavior well-defined in C#? In C++, such code invokes undefined/unspecified behavior. Please also quote the relevant sections from the language specification in your response!

Community
  • 1
  • 1
Nawaz
  • 353,942
  • 115
  • 666
  • 851
  • 2
    Is there any aspect of your question not answered by various people in [C#: Order of function evaluation (vs C)](http://stackoverflow.com/questions/1215236/c-order-of-function-evaluation-vs-c)? – Gabe Jan 10 '11 at 06:46
  • @Gabe : the first two statements in my question is slightly different than what is discussed in the other topic. I may be wrong, though. – Nawaz Jan 10 '11 at 06:59
  • @All : please don't vote for closing this topic. there is no harm if I get some answer to first two statements in my question. – Nawaz Jan 10 '11 at 07:01
  • 1
    I believe [Pavel's answer](http://stackoverflow.com/questions/1215236/c-order-of-function-evaluation-vs-c/1215257#1215257) quotes the proper section of the spec to answer all of your questions. – Gabe Jan 10 '11 at 07:04
  • @Gabe : it looks like. But leppie has some doubts there. – Nawaz Jan 10 '11 at 07:09
  • 1
    It's not like this is hard to find in the specification. Hint: check the table of contents. – Eric Lippert Jan 10 '11 at 07:18
  • 2
    If this subject interests you, you might also see my articles: http://blogs.msdn.com/b/ericlippert/archive/tags/precedence/ – Eric Lippert Jan 10 '11 at 07:20

2 Answers2

11

The key here is the table in "1.4 Expressions", and "7.3.1 Operator precedence and associativity". I won't duplicate the table from 1.4, but to quote 7.3.1:

  • Except for the assignment operators, all binary operators are left-associative, meaning that operations are performed from left to right. For example, x + y + z is evaluated as (x + y) + z.
  • The assignment operators and the conditional operator (?:) are right-associative, meaning that operations are performed from right to left. For example, x = y = z is evaluated as x = (y = z).

The first is logically expanded (or: use the associativity rules) as:

i = i + ++i;

here, the order (from the table) is pre-increment, then additive, then assignment - so we should expect i to double plus one. And indeed, with i=6, we get 13 as expected.

a[++i] = i;

again from the table, order should be array access, pre-increment, assignment - so I would expect the i+1'th value to be i+1. And indeed, checking:

    int[] a = { 0, 0, 0, 0, 0 };
    int i = 2;
    a[++i] = i;

we do indeed get {0, 0, 0, 3, 0}.

With the last, method invocation takes priority over subtraction, then it is left-to-right; so it should be fun(), gun(), -, assignment.

Marc Gravell
  • 1,026,079
  • 266
  • 2,566
  • 2,900
  • Or `gun(), fun(), -, assignment` – leppie Jan 10 '11 at 07:07
  • @leppie - left associative, surely (section 7.3.1) – Marc Gravell Jan 10 '11 at 07:09
  • But only on the values, hence after they have been evaluated (method invoked). In general, it is left to right, but I dont see any guarantees. – leppie Jan 10 '11 at 07:13
  • 1
    I think there's one more sentence that needs to be quoted from the spec: `The order of evaluation of operators in an expression is determined by the precedence and associativity of the operators.` *In general*, precendence and associativity don't necessarily determine the order of evaluation (C being one example where `x + y + z` = `(x + y) + z`, but the order of evaluation is undefined). – Heinzi Jan 10 '11 at 07:14
  • 7.4.1 actually covers this: http://msdn.microsoft.com/en-us/library/Aa691335, it has nothing to do with operators. They seems to 'guarantee' it, but still say the compiler is free to rearrange the execution if it can prove there are no side effects. Not much of a guarantee in that case ;P – leppie Jan 10 '11 at 07:21
11

People always get this so confused, which is unfortunate because in C# it is extremely straightforward. The rules are:

  • subexpressions are observed to be evaluated left to right when observed from the executing thread, period, end of story. (Order of evaluation is permitted to be observed to be different by some other thread if some other thread is watching the side effects.)

  • the order in which the operators execute is determined by their precedence and associativity.

Those are the only two relevant rules, and they completely define the behaviour of the code you give. In

i += ++i; 

first i is evaluated, then ++i is evaluated, and then the += is executed.

a[++i] = i; 

First 'a' is evaluated, then ++i is evaluated, then the indexing operator runs, then i is evaluated, then the assignment happens.

int result =  fun() - gun(); 

first result is evaluated, then fun, then gun, then the subtraction, then the assignment.

Please also quote the relevant sections from the language specification in your response!

You are perfectly capable of looking in the table of contents. It's not hard to find.

Eric Lippert
  • 647,829
  • 179
  • 1,238
  • 2,067
  • @leppie: I am extremely confused by your question. How else would you know where to store the value produced by the right side if you didn't *evaluate* the left hand side of the assignment and from it produce a *variable*? – Eric Lippert Jan 10 '11 at 07:35
  • Now I am also confused :) Let me rephrase; why does a local slot declaration (aka `result`) need to be evaluated? It contains no meaningful (or usable) value before initialization (iow first assignment). – leppie Jan 10 '11 at 07:39
  • 2
    @leppie: It is not being evaluated for the *contents* of the variable, it's being evaluated for the *location*. The contents are irrelevant, but how are you going to figure out the location for the assignment without evaluating the left hand side? My point is that the evaluation of the left hand side happens *before* the right hand side: **in C# the subexpressions are always evaluated left to right** and that includes subexpressions such as local variables being evaluated to determine their addresses. – Eric Lippert Jan 10 '11 at 07:42
  • 5
    @leppie: Maybe this would make you feel better. In "A().B().C[D()].E = F();" the evaluation of field E has to happen before the evaluation of function call F(). In order to evaluate field E to determine its location, we must first evaluate A(), B(), C(), D() and execute the index operator. **The left hand side of the assignment is evaluated before the right hand side**. It is evaluated to determine the *location* that the right hand side is going to be assigned to. – Eric Lippert Jan 10 '11 at 07:44
  • 2
    Thanks, crystal clear example :) – leppie Jan 10 '11 at 07:48