66
a = 5
b = a + (a = a + 5)

result b = 15

Why the first 'a' do not changes after that (a = a + 5)? But why second one changes? What exactly is happening here by steps?

fastec
  • 907
  • 1
  • 8
  • 18
  • 10
    The first `a` is evaluated first. It being _first_ and all. – Peter Duniho Jan 14 '15 at 07:33
  • Perhabs the second line is evaluated from left to right, resulting in `b = 5 + ( 10 )`, which is `15`. – Codor Jan 14 '15 at 07:33
  • 1
    The expression is parsed left to right so a is 5 when it is first accessed – JConstantine Jan 14 '15 at 07:33
  • 159
    Everything aside, don't write code like that. – Soner Gönül Jan 14 '15 at 07:39
  • 4
    Reading the answers it would also be interesting to clarify `b = (a = a + 5) + a` – hultqvist Jan 14 '15 at 09:12
  • 1
    It seems purely academic to know why this happens which isn't bad. Regardless why, I really hope nobody is writing code like this. – Corey Ogburn Jan 14 '15 at 16:13
  • @phq; `b` will have value `20`. – haccks Jan 14 '15 at 18:41
  • Shouldn't we be open to new ways of coding? Such as closures and tertiary operators? – zardilior Jan 15 '15 at 00:41
  • 1
    If someone interested there is an example `public static int NOD(int a, int b) { while (b != 0) b = a % (a = b); return a; }` It is "Greatest common divisor" function. – fastec Jan 15 '15 at 02:38
  • 13
    @zardilior - Re *Shouldn't we be open to new ways of coding?* No, not always. The right answer to this question is DON'T DO THAT, in all caps. C and C++ have a simple answer: Nasal demons might well fly out of your nose. Haskell and other function languages try to have a somewhat simpler (but ultimately wrong) answer: That's illegal. (It's ultimately wrong because of the self-referential problem. Read *Gödel, Escher, Bach: An Eternal Golden Braid* for details.) Languages such as C# that try to make sense out of this are just fooling themselves. In all languages, the answer is DON'T DO THAT. – David Hammen Jan 15 '15 at 05:55
  • @DavidHammen: "It's ultimately wrong because of the self-referential problem" I feel like you have to elaborate on that one. I'm not going to read a whole book to find the justification :) – Niklas B. Jan 15 '15 at 11:25
  • @NiklasB. - Determining whether a system is somehow self-referential is akin to determining whether the program will halt. – David Hammen Jan 15 '15 at 12:20
  • @David So how does that relate to language design, in particular purely functional languages? – Niklas B. Jan 15 '15 at 13:46
  • All programs should be written such that it is readable. Almost certainly you will be back and making changes before you know it. So write code such that, anyone who reads it, can easily understand the logic. Code has to be maintained over time and most certainly it will *not* be you, who is later making changes and fixing bugs! This kind of code depends on the knowledge of a resource. Most real world programs do not require any fancy work. So KISS, is the way to go. – ShaQ.Blogs Jan 15 '15 at 08:07
  • 1
    @PeterDuniho There's no need to be a smart arse. People are here to learn. – Razor Feb 05 '15 at 22:03

4 Answers4

161

Expressions are evaluated left to right - always, regardless of grouping. So it's equivalent to:

a = 5;

int lhs = a; // 5
int rhs = (a = a + 5); // Increments a by 5 (i.e. a=10), and rhs=10
b = lhs + rhs; // 15

So after this has executed, a will be 10. But that only happens after a has been evaluated for the first operand of the main addition, which is why the result is 15 rather than 20.

It's really important to understand the part about evaluation order not being the same as precedence. Consider this:

int x = First() + Second() * Third();

Precedence means that the multiplication applies to the results of calling Second() and Third() - but First() is still evaluated first. In other words, this statement is equivalent to:

int lhs = First();
int rhs = Second() * Third();
int x = lhs + rhs;

See Eric Lippert's blog post on predence, associativity and ordering for more details.

I would strongly advise against writing code like this though.

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • 3
    So _parens_ are not getting **higher** priority you meant? Like the OP did `(a = a + 5)`.. – Arup Rakshit Jan 14 '15 at 07:36
  • 1
    But, I am not really satisfied with your answer. as you explain this BY PARTS, means you evaluate this expression in two different statements (Left & Right). So, as far your answer is concerned, you are right. but the question's statement is different & EVALUATED IN SINGLE STEP. – Waqas Shabbir Jan 14 '15 at 07:38
  • 14
    @ArupRakshit: The parentheses are for *grouping*, not *order*. The LHS of the expression is *always* executed first, regardless of the grouping. – Jon Skeet Jan 14 '15 at 07:39
  • 26
    @WaqasShabbir: No, the whole point of the answer is that my statements are *equivalent* to the original statement. It's not like the original statement is being performed atomically in the CPU. The compiler is breaking it down into multiple steps (and even my answer could be broken down into extra steps for the intermediate addition). – Jon Skeet Jan 14 '15 at 07:40
  • 1
    Isn't the order unspecified? – Erbureth Jan 14 '15 at 09:19
  • 10
    @Erbureth: in C or C++ the order is unspecified, but this question isn't about those languages. – Steve Jessop Jan 14 '15 at 09:41
  • @SteveJessop do you have a citation for that? just curious. – Umur Kontacı Jan 14 '15 at 15:36
  • @UmurKontacı: Do you mean about C/C++, or about C#? It's all pretty clear in the C# language specification. – Jon Skeet Jan 14 '15 at 15:39
  • This somehow reminds me of my highschool math lessons. I kept failing the tests until I learned programming, that magically enlightened me on (basic) math. So, thanks for putting a smile on my facewhile enjoying memories @JonSkeet! – RvdV79 Jan 14 '15 at 21:35
  • @JonSkeet I meant in C/C++ since Steve has mentioned the order is unspecified in those languages – Umur Kontacı Jan 15 '15 at 00:07
18

Unlike C and C++, the order of evaluation of subexpressions are left to right in C#. That's why the expression

j= ++i + ++i ;   

has well defined behavior in C# while undefined in C and C++.

In expression

b = a + (a = a + 5)  

left a will be evaluated first, then a+5 is evaluated and assigned to a and after addition of both evaluated subexpression, b will have value 15.

haccks
  • 104,019
  • 25
  • 176
  • 264
  • In your first example, both sides of the addition equation are the same, so even if it is parsed RTL, the answer should be the same. – Brian Hannay Jan 14 '15 at 16:56
  • 2
    @BrianHannay;C standard says that: ***If a side effect on a scalar object is unsequenced relative to either a different side effect on the same scalar object** or a value computation using the value of the same scalar object, **the behavior is undefined***. This makes first statement come under undefined behavior. While second statement invokes UB because C standard says: *If there are multiple allowable orderings of the subexpressions of an expression, the behavior is undefined if such an unsequenced side effect occurs in any of the orderings*..... – haccks Jan 14 '15 at 18:19
  • ......Just print the value of `j` after `j= ++i + ++i ;` in both C and C# and see the [effect](http://stackoverflow.com/q/24735290/2455888). BTW, here is output for [C](http://ideone.com/8NWsCR) and [C#](http://ideone.com/0UTnZK). – haccks Jan 14 '15 at 18:23
  • Saying "j = ++i + ++i is undefined" means, I think, that the code could implement either increment first. As it happens, either choice yields the same result. But if you had "j = ++i + --i", then the result could take on different values depending on whether the increment or decrement was done first. – user3294068 Jan 14 '15 at 21:26
  • 4
    @user3294068: That would be correct if it were "implementation defined". But it's _undefined_, which means the program can do anything, including crash. – Mooing Duck Jan 14 '15 at 23:18
  • @user3294068; I am not saying it my own that its undefined, but C standard says that. Read my first comment. – haccks Jan 14 '15 at 23:22
10

The expression is always evaluated from left to right & then assigned to whatever on left hand. As

  a = 5
  b = a + (a = a + 5)
\\b = 5 + (a = 5 + 5)
  b = 15
Waqas Shabbir
  • 755
  • 1
  • 14
  • 34
  • 11
    You said *But, I am not really satisfied with your answer* for Jon's answer. That's fine, but how does your answer is any better than Jon's answer? Also it's not clear what you're trying to say with line 3 `b = 5 + (a = 5 + 5)` At least annotate it with comment, so that it makes sense. – Sriram Sakthivel Jan 14 '15 at 07:51
  • 15
    *"but how does your answer is any better than Jon's answer?"* - that's a trivial question. It never is! – Dion V. Jan 14 '15 at 07:55
  • 1
    @SriramSakthivel, yes you are right. I comment it. And i explains only that the expression is always evaluates from left to right. and the result is assigned to operand on left of assignment statement. – Waqas Shabbir Jan 14 '15 at 08:00
  • 8
    Your code example isn't explaining very well. It implies that it is substituting the value of a in both parts of the expression at the same time which it isn't. In this case it doesn't matter but it might lead people to incorrectly apply the same logic to get `b = (a = a + 5) + a` leads to `b = (a = 5 + 5) + 5` in a single step which is wrong. You need to show that it evaluates the LHS fully first and then starts evaluating the right hand side by for example including `b = 5 + (a = a + 5)` as one of your intermediate steps. – Chris Jan 14 '15 at 13:13
  • 1
    I totally agree with @Chris. I'd also add `b = 5 + (a = 10)` and `b = 5 + 10 // a is now 10` as additional intermediate steps. The last step I mentioned would also clearly indicate when a's value actually changes (you could perhaps add "a is still 5" at the step before or "a was 5 up to now" at that step to make this change more clear). – Bernhard Barker Jan 14 '15 at 13:54
  • yes @Chris, i want to explain the same thing as you told. i explains that the expression evaluates from left to right. and result assigns from right to left. As in case of b = a + (a = a + 5), the first 'a' is assigned first (because on left side), and in case of b = (a = a + 5) + a, the statement '(a = a + 5)' evaluates first (because on left side) & the value of 'a' is changed in this particular case. – Waqas Shabbir Jan 15 '15 at 07:26
3

We always work left to right the Parens just group parts of the sum.So just remember always go left to right. I have gone step by step below

start with the question

a = 5

b = a + (a = a + 5)

So now change the first 'a' to a 5

b = 5 + (a = a + 5)

now lets do the sum in the parens

b = 5 + (a = 5 + 5)

This gives us

b = 5 + 10 or you could say b = 5 + (a = 10)

and the answer is

b = 15

also now

a = 10