Two posers for you


What is the output of the following code, and why?


[Update: By “why“, I mean “what part of the C# spec controls this behavior?“]


class Test
{
  public static void Main()
  {
    int z = 2;
    z += ++z+5*z++;
    System.Console.WriteLine(“Yak! {0}”, z);
  }
}


What about this code?


class Test
{
  public static void Main()
  {
    int z = 2;
    z += (5*z++)+(++z);
    System.Console.WriteLine(“Yak! {0}”, z);
  }
}


Extra credit: What is the defined output for C++, and why?

Comments (33)

  1. Scott Wisniewski says:

    The C++ output is implementation defined, because the C++ standard doesn’t specify when in an expression the "set" portion of any increment instructions should be executed.

  2. John says:

    The answer is "it doesn’t matter" right?

    Because no-one would be evil enough to write a statement that used the ++ operator in an expression!

    Right? Seriously, you guys.. 🙂

  3. Thanks for that Eric… very intruiging 🙂

    You failed my code review though!

  4. Doug McClean says:

    Is it "Yak! 28"?

  5. Scott Wisniewski says:

    20 and 16.

    It apears that in both cases the += is using the value of Z at the start of the expression.

  6. AndrewSeven says:

    Poser one : the guy pretending to be programmer.

    Poser two : the senior who fixed it into the second version.

    The output of the code might be a job opening but is more likely to produce a lecture.

    http://weblogs.asp.net/andrewseven/articles/Ramblings.aspx

  7. Scott Wisniewski says:

    Let me clarify….

    It apears that in both cases, variable += expression is doing this…

    1. get the value of "variable", store it in a temp register

    2. evaluate expression

    3. add the evaluated expresion to the value of Z in the temp register

    4. set the value of Z with the value from the temp register

  8. haacked says:

    The first is 20

    z = 2 + 3 + 5(3) = 20

    The second is 16

    z = (10 + 1)+(2)+ 3

  9. Hang on, let me paste it in Visual Studio… 🙂

  10. Sean Chase says:

    My SWAG is that the pre-increment expression is firing after all of the orders of operation, so you get something like this:

    int z = 2;

    z += 2/*++z*/ + 5 * 3 /*z++*/;

    ++z;

    System.Console.WriteLine("Yak! {0}", z);

    I won’t bother with the others unless I find out I’m on the right track. Fun stuff!

  11. Sean Chase says:

    My SWAG is that the pre-increment expression is firing after all of the orders of operation, so you get something like this:

    int z = 2;

    z += 2/*++z*/ + 5 * 3 /*z++*/;

    ++z;

    System.Console.WriteLine("Yak! {0}", z);

    I won’t bother with the others unless I find out I’m on the right track. Fun stuff!

  12. Sean Chase says:

    Holy double post batman – sorry about that. OK, maybe I’m chasing up the wrong tree again, but I’m thinking that the second is another order of operations vs. increment/decrement expression:

    int z = 2;

    z += (5 * /*z*/2) /*++operator*/+ 1 + /*value of z*/(2);

    ++z;//then this happens???

  13. Wes says:

    Here is what I found in the C# spec that governs the rules for this problem.

    Sec 7.13.2 Compound Assignment states "If the return type of the selected operator is implicitly convertible to the type of x, the operation is evaluated as x = x op y, except that x is evaluated only once"

    Sec 7.2 Operators states "The order of evaluation of operators in an expression is determined by the precedence and associativity of the operators"

    Sec 7.2.1 Operator precedence and associativity states "Except for the assignment operators, all binary operators are left-associative, meaning that operations are performed from left to right."

    Sec 7.6.1 Prefix operator states "The result of ++x is the value of x after the operation"

    Sec 7.5.9 Postfix operator states "The result of x++ is the value of x before the operation"

    Working through the expression using the precedence table in section 7.2.1

    z += ++z + 5 * z++;

    z = z + (++z + 5 * z++); by 7.13.2

    z = 2 + (++z + 5 * z++);

    z = 2 + (++2 + 5 * z++);

    z = 2 + (3 + 5 * z++); // z has value 3 now

    z = 2 + (3 + 5 * 3++);

    z = 2 + (3 + 5 * 3); // z has value 4 now

    z = 2 + (3 + 15);

    z = 2 + (18);

    z = 20; // z has value 20 now

    So the output is "Yak! 20"

    Looking at the second expression

    z += (5 * z++) + (++z);

    z = z + ((5 * z++) + (++z));

    z = 2 + ((5 * z++) + (++z));

    z = 2 + ((5 * 2++) + (++z));

    z = 2 + ((5 * 2) + (++z)); // z has value 3 now

    z = 2 + ((10) + (++z));

    z = 2 + (10 + (++3));

    z = 2 + (10 + (4)); // z has value 4 now

    z = 2 + (14);

    z = 16; // z has value 16 now

    So the output is "Yak! 16"

    As far as the in C++ it is undefined because to the order of evaluation is undefined, from section 6.2.2 Evaluation Order in Programming Languages Third Edition by Bjarne Stroustrup. That section also states that it is undefined because better code can be generated in the absence of restrictions on expression evaluation order.

    Wes

  14. Wes says:

    Sorry the C++ book is "The C++ Programming Language" Third Edition. Just in case someone didn’t know. 🙂

  15. Jiho Han says:

    16 each?

  16. The first answer would be 22, since it’s defined [1] that the operator precedence will be the primary operator (z++ // will be calculated in next line), followed by the unary operator (++z), the multiplication operator (5*z), the additive operator (+) and lastly the assignment operator.

    The second answer would be 16, since the precedence will be the primary operator (z++ // will be calculated in next line), followed by the multiplication operator (5*z), the unary operator (++z), the additive operator (+) and lastly the assignment operator.

    [1] http://msdn.microsoft.com/library/en-us/csspec/html/vclrfcsharpspec_7_2_1.asp

  17. Isn’t it funny that z += z++; produces the same result as z += z;

    😉

  18. Eric,

    frankly: it doesn’t matter. code like that should not be written (and i know that you know). write-only code like that needs some serious rewriting. 🙂

    WM_MY0.02$

    thomas woelfer

  19. Kael Rowan says:

    Wes is right about how the expression gets evaluated. What’s interesting though is that the order of evaluation doesn’t quite seem to match what one would expect from the chart in 7.2.1. Lets take a simpler example by removing the compound expression and comparing the two following expressions:

    – [1] –

    int z = 2;

    int y = z + ++z;

    – or [2] –

    int z = 2;

    int y = ++z + z;

    According to the chart, primary-expressions are evaluated first, and then unary-expressions after. A primary-expression can be a primary-no-array-creation-expression, which can be a simple-name, which is an identifier (such as z). A unary-expression comes after, which could be a pre-increment-expression (such as ++z). Therefore the statements should be evaluated as follows:

    [1]

    x = z + ++z; // start

    x = 2 + ++z; // primary-expression evaluated

    x = 2 + 3; // unary-expression evaluated, z is now 3

    x = 5; // what you would expect

    [2]

    x = ++z + z; // start

    x = ++z + 2; // primary-expression evaluated

    x = 3 + 2; // unary-expression evaluated, z is now 3

    x = 5; // same answer as in [1]

    If you run this through version 7.10.3052.4 of the C# compiler you’ll actually get something different for [2]:

    x = ++z + z; // start

    x = 3 + z; // unary-expression evaluated first! z is now 3

    x = 3 + 3; // the primary-expression ‘z’ is evaluated which is now 3

    x = 6; // Yak!

    Hopefully I’m just misinterpreting the spec somehow, but shouldn’t simple-name expressions such as ‘z’ be evaluated before unary-expressions such as ++z?

    -Kael

  20. Wes says:

    Kael,

    Actually I don’t think that z is evaluated first in fact I would expect that your second example would have an answer 6. Unless I’m reading the spec wrong I think the unary and prefix operator have the same precedence so they are evaluated left-to-right.

    Wes

  21. Robert Kozak says:

    Definately 20 and 16.

    This isnt all that hard.

    First:

    int z = 2;

    z += ++z+5*z++;

    unary-expressions first from left to right

    z = 2 + (3) + (5 * 3);

    Then the mulitplication

    z = 2 + 3 + 15

    Then Addition

    z = 20

    Second one:

    int z = 2;

    z += (5*z++)+(++z);

    brackets first

    z = 2 + ((5*2)++) + (++z);

    then unary

    z = 2 + 10++ + (3);

    then addition

    z = 2 + 11 + 3;

    z = 16

    Simple no?

  22. Kael Rowan says:

    Wes,

    Is the occurance of z without any operators applied (such as x = z) considered having a unary operator applied? I guess my question is where to identifiers without any unary operators fall in the operator precedence and associativity table? I intrepreted the spec to mean that an identifier (i.e. simple-name, i.e. primary-no-creation-expression, i.e. primary-expression) came first under the "Primary" category in the operator precedence and associativity table:

    primary-expression: // "Primary" Category

    primary-no-array-creation-expression

    array-creation-expression

    primary-no-array-creation-expression:

    literal

    simple-name

    parenthesized-expression

    member-access

    invocation-expression

    element-access

    this-access

    base-access

    post-increment-expression

    post-decrement-expression

    object-creation-expression

    delegate-creation-expression

    typeof-expression

    checked-expression

    unchecked-expression

    simple-name:

    identifier // z

    unary-expression: // "Unary" Category

    primary-expression

    + unary-expression

    – unary-expression

    ! unary-expression

    ~ unary-expression

    pre-increment-expression // ++z

    pre-decrement-expression

    cast-expression

    Here’s a link to the docs I’m looking at:

    ms-help://MS.VSCC.2003/MS.MSDNQTR.2003JUL.1033/csspec/html/vclrfcsharpspec_7_2_1.htm

    -Kael

  23. Wes says:

    Following a left-to-right derivation of the grammar rules I would assume that ++z is evaluated first:

    expression

    conditional-expression

    conditional-or-expression

    conditional-and-expression

    inclusive-or-expression

    exclusive-or-expression

    and-expression

    equality-expression

    relational-expression

    shift-expression

    additive-expression

    additive-expression + multiplicative-expression

    multiplicative-expression + multiplicative-expression

    unary-expression + multiplicative-expression

    pre-increment-expression + multiplicative-expression

    ++unary-expression + multiplicative-expression

    ++primary-expression + multiplicative-expression

    ++simple-name + multiplicative-expression

    ++identifier + multiplicative-expression

    ++z + multiplicative-expression

    ++z + unary-expression

    ++z + primary-expression

    ++z + simple-name

    ++z + identifier

    ++z + z

    I don’t think the precedence matters in this case because there is no conflict, meaning that the ‘+’ in the middle is of lower precedence than both so you need to evaluate the arguments for the ‘+’ from left-to-right.

    If I’m wrong here please someone correct me.

    Wes

  24. Sean Chase says:

    Just for kicks, compile the code and open the assembly with Anakrino. The output is nowhere near being correct. 🙂

  25. Kael Rowan says:

    Hi Wes,

    I like the explicit grammar construction you provided, but I’m trying to figure out how that shows us that ++z would be evaluated first. How does expression evaluation follow grammer production? I would have assumed that on line 12 of your production it would have evaluated multiplicative-expression first since it has higher precedence over additive-expression. But if it constantly goes from left-to-right, the following production would produce the wrong evaluation:

    x + y * z

    expression

    conditional-expression

    conditional-or-expression

    conditional-and-expression

    inclusive-or-expression

    exclusive-or-expression

    and-expression

    equality-expression

    relational-expression

    shift-expression

    additive-expression

    additive-expression + multiplicative-expression

    multiplicative-expression + multiplicative-expression

    unary-expression + multiplicative-expression

    primary-expression + multiplicative-expression

    simple-name + multiplicative-expression

    identifier + multiplicative-expression

    x + multiplicative-expression

    x + multiplicative-expression * unary-expression

    x + unary-expression * unary-expression

    x + primary-expression * unary-expression

    x + simple-name * unary-expression

    x + identifier * unary-expression

    x + y * unary-expression

    x + y * primary-expression

    x + y * simple-name

    x + y * identifier

    x + y * z

    Here we all know that y * z should be evaluated first, but which point in the grammar production explains this (and correspondingly where is the corresponding point in the x = ++z + z production that explains why ++z is evaluated before z)?

    Thanks again for explaining this. I hope others reading this thread are learning from it as much as I am! 🙂

    -Kael

  26. Kael Rowan says:

    Sean,

    I took your advice and opened it with Lutz’s .NET Reflector and it’s nowhere near correct either:

    int num1;

    num1 = 2;

    num1 = (num1 + 1);

    num1 = (num1 + 1);

    num1 = (num1 + ((num1 + 1) + (5 * num1)));

    Console.WriteLine("Yak! {0}", num1);

    Hmm, have we discovered some new form of obfuscation? (As if the original code isn’t obfuscated enough already)

    -Kael

  27. Dave says:

    I just think it’s bloody hilarious that this much work has to go into decoding two lines. Definitely not a Pit of Success.

  28. Wes says:

    Kael,

    With your particular example x + y * z, y has two possible operators to be used with thus there is a conflict and * has higher precedence so it used.

    What typically happens with these type expressions is a parse tree is created using the grammar rules and then that tree is evaluated using a pre-order traversal. I would draw out your parse tree but it is kind of hard to do in the comments 🙂

    Essentially what is happening for your expression is that you are going to add x to the result of the multiplicative-expression which is y * z. Where as with the ++z + z you are going to add the result of the pre-increment-expression to the result of the multiplicative-expression.

    I think if you look at the parse trees for these expressions it will help your understanding.

    Wes

  29. Very cool! I really like how this forces you to actually understand expressions (err, forces someone like Wes to explain it to us ; ).

    I’ve recently made a C# compiler[1] using antlr, and expressions were really hard (for me) to get right. I thought it was all debugged, but the above code acutally caught two errors – one with multiple classes without a namespace, and one converting the tree to a C#Dom (it missed the very last preinc expressions inside parens). There actually might be more to that though (just x=(++y); seems to have a problem too) — bugs are like the mice in the house, if you see two, there are 60 more in the walls. I dearly hope I don’t have to revisit the expression grammar(!), but thanks for the hostile code in any case : ).

    The project I’m working on exports C# to the swf (flash) stack environment. Interestingly the above code in actionscript (flash’s language) also gives 20 and 16. I guess it is normal enough to convert the += like that then..? I really fear these tiny differences in the two environments, it is really hard to test for them, or even know you need to. I know it is all nicely laid out in the C# spec, but you hate pulling out your magnifying glass on a document that size ; ).

    Anyway, I think quirky code like this is really useful. Of course you wouldn’t use it or write it, but it really helps solidify your ‘mental image’ of what is going on in your code. And like in this case, it often exposes one of those little ‘truths in a nutshell’ (like marc’s z += z++; -> 4) that can one day save untold suffering from being cast upon your bacon.

    Thanks for the post,

    Robin

    [1]no home yet, just a beta at http://blog.debreuil.com