Andreas Grech
Andreas Grech

Reputation: 107940

C#: Order of function evaluation (vs C)

Take the following C code (K&R pg. 77) :

push(pop() - pop()); /* WRONG */

The book says that since - and / are not commutative operators, the order in which the 2 pop functions are evaluated is necessary (obviously, to get the correct result)...and thus you have to put the result of the first function in a variable first and then proceed with the arithmetic, like such:

op2 = pop();
push(op2 - pop());

Apparently this is because the compiler can't guarantee in which order the functions are evaluated (...why?)


My question is, does C# do this same thing? as in, do I have to worry about this sort of thing when working with C# ? and for that matter, any of the other higher level languages ?

Upvotes: 7

Views: 2400

Answers (8)

Pavel Minaev
Pavel Minaev

Reputation: 101595

Order of evaluation is well-defined in C# in all cases, and is left-to-right. From C# language spec (§7.3):

The order of evaluation of operators in an expression is determined by the precedence and associativity of the operators (§7.2.1). Operands in an expression are evaluated from left to right. For example, in F(i) + G(i++) * H(i), method F is called using the old value of i, then method G is called with the old value of i, and, finally, method H is called with the new value of i. This is separate from and unrelated to operator precedence

In case of C++, it's not that the order couldn't be defined; it's that allowing the order to be undefined allows the compiler to better optimize code.

Upvotes: 1

Mark Brackett
Mark Brackett

Reputation: 85665

The book says that since - and / are not commutative operators, the order in which the 2 pop functions are evaluated is necessary (obviously, to get the correct result)...and thus you have to put the result of the first function in a variable first and then proceed with the arithmetic.

That's not quite correct. K&R allowed rearrangement of commutative operators (done away with in ANSI C). Since suibtraction is not commutative, it is not re-arrangeable...under that rule, at least.

(Un)fortunately, C also doesn't define the order of evaluation (outside of a fairly small scope) - which means the compiler can call those functions in any order (as long as the result of pop() - pop() is fully evaluated before calling push())

Which - in this case, results in the same problem - but for a different reason.

Upvotes: 1

Michael Burr
Michael Burr

Reputation: 340218

To answer your question about why C doesn't define the order of operation, it's simply because the inventors of C decided it would be valuable to give compiler implementors the opportunity to optimize expression evaluation. They also decided that it was more valuable than giving programmers certainty in expression evaluation.

Remember that when C was originally developed, machines were much less capable than today, and there was more interest in giving compilers the optimization leeway. Today, there is often more weight given to safer, more predicatble code.

Upvotes: 5

Michael Donohue
Michael Donohue

Reputation: 11876

In C# it is left to right: http://blogs.msdn.com/oldnewthing/archive/2007/08/14/4374222.aspx


Re: C++ order

Apparently this is because the compiler can't guarantee in which order the functions are evaluated (...why?)

Any particular compiler can guarantee the order. The problem is that the language spec does not specify an order, so each compiler can do whatever it wants. This means you have to add a sequence point between the two method calls if you want to guarantee ordering.

Upvotes: 11

Guffa
Guffa

Reputation: 700382

No, C# doesn't do the same thing. It doesn't use evaluation boundaries the same way as C does, where the order of execution between the boundaries is undefined. The expression is evaluated left to right, just as you would expect.

If you are ever uncertain of the order of execution, or if you want to make the code clearer, you should use a local variable for an intermediate result. Local variables are very cheap to allocate as they are allocated on the stack, and in some cases the compiler is even able to put the variable in a register so that it's not allocated at all. Besides, depending on how the expression looks the compiler may need to use a local variable to store the intermediade result anyway.

Upvotes: 2

Matthew Scharley
Matthew Scharley

Reputation: 132284

Colour me surprised, but apparently C# does the "right" thing, and evaluates left to right:

void Main()
{
    Console.WriteLine(Pop() - Pop()); // Prints -1
}

// Define other methods and classes here
bool switchVar = true;
int Pop()
{
    int ret;
    if (switchVar)
        ret = 1;
    else
        ret = 2;
    switchVar = !switchVar;

    return ret;
}

Upvotes: 0

Sam Harwell
Sam Harwell

Reputation: 99889

From Fabulous Adventures In Coding: Precedence vs Associativity vs Order:

Another way to look at it is that the rule in C# is not "do the parentheses first", but rather to parenthesize everything then recursively apply the rule "evaluate the left side, then evaluate the right side, then perform the operation".

Upvotes: 2

nagul
nagul

Reputation: 2263

I believe in C# the argument list is evaluated in order, from left to right.

Upvotes: 0

Related Questions