Order of visited expressions:

IceAzul

Freshman
Joined
Jun 7, 2005
Messages
43
C#:
int[] array = new int[10];
int number = 0;

array[number++] = number++ // array[0] = 1;
array[number++] = number++ // array[2] = 3;
array[number++] = number++ // array[4] = 5;
etc...

Why is the destination visited before the expression?!?! Isn't that counter intuitive? I know it probably has something to do with the parsing order, but I just found it bothersome.
 
I don't see how that is counter-intuitive. When there is no other precedence the default precedence is left-to-right. Why should either the assignment target or the value be evaluated first? You need to calculate a pointer for the assignment and you need to calculate a value to be assigned, but at the actual point of the assignment it doesn't matter which was calculated first, as long as you have both. "=" is a binary operator, just like the addition operator, the member access operator, the multiplication operator, etc.. Even with the assignment operator, the left-hand value is always calculated first.
 
In other words, you have to know where you will put something before you can put it there.
 
Well, what does that really say, mskeel? The confusion seems to be that something like
C#:
someArray[someIndex] = someValue;
is viewed as a two-part operation. You can think of it as calculate the value and store the value. You can also think of it as find the desination and then put the value there. Neither of the two is the case. I noticed that you used the term "visited," IceAzul. There is a difference between determining the destination and actually accessing ("visiting") it.

There are three parts to this operation: evaluate the destination, evaluate the value, and perform the assignment. The third part is dependent upon the first two parts, but each of the first two parts is independent. There is no need for one to be evaluated before the other.

In other words, yes, you need to know where you will put something before you can put it there, but you also need to what to put there before you can put it there. The order in which these things are done is (presumably) simply a matter of the order that they appear in the syntax. There is no other reason to do it any particular way.

If you were to hand-write the MSIL you could do it in which ever order you like. The stelem (store element) MSIL opcode lends itself to evaluating the destination first, but with an extra opcode or two it can be done the other way. As to which way is more intuitive, it depends on what analogy you use to understand assignment within an array.

If I had to guess without actually writing the code and executing or decompiling it and I hadn't looked at a decent amount decompiled code, I would probably expect that the value to be assigned would be calculated first, but I wouldn't count it as more than a guess.
 
I was just assuming that since the assignment of a value to a location in memory goes after the value is figured out, you would check the location in memory right before that happens. In my view, it would be figure out the value -> find the destination -> assign it there. To figure out a destination, then a value, and then assigning the value to the destination seems to me to be out of order, regardless of the order of the expression. I do understand the idea that an assigment is merely an operation, it's just that I always viewed the following as being right to left.
C#:
array[number++] = array[number++] = array[number++] = number++ ;
 
The target has to be resolved before you can make an assignment so that you have an opportunity to remove potential ambiguity and use the correct assignment operator for the target. This way, an exception can be thrown if it is not possible to convert the source to the target's type, or you can throw a core dump immediately in the event of a memory exception for the target.

Then again, I suppose all of that really is just arbitrary and it could be done in a different order if you really wanted. I guess I never really took the time to think about it. I've always looked at things in terms of dereferencing pointers which takes precedence over assignment.
 
mskeel said:
use the correct assignment operator for the target
Not quite sure what you meant by that. Do you mean operator/casting overloads? I can't really think of any scenario where a "correct assignment operator" can't be determined at compile time.
 
Since the order of operations is arbitrary, I think that it's a bad idea to depend on it with calls like

array[i++] = i++

It's just asking for trouble.

But because the order of operations is not necessarily "set in stone", then even this is ambigous (unfortunately):

array = i++

I would prefer to read the above as the 'i++' occurring after the assignment is complete, but it would seem that this is not necessarily written in stone, and so it *could* go the other way -- as IceAzul would seem to prefer. (I'm not sure why though, I think the "++" happening *last* is the most intuitive to me, but maybe that's just me.)

The other possibility is that the RHS then LHS evaluation order *IS* written in stone somewhere. Ok, not as far as the IL is concerned, but it could be a C# rule (or even C/C++ rule). Assuming that "RHS then LHS" is in-fact a rule, then having any '++' on the LHS is probably a bad idea in any situation, or at least certainly if the RHS has a reference to the same variable.

Hmm, I wonder what happens here:

Array = ++i;

I'm guessing that the LHS is evaluated first, and then i is incremented, then the RHS. But maybe it's "++" precedence?? I doubt it, but it would be interesting. If this did occur then the LHS and RHS are in-fact not 100% independent. But I'm betting that they are...

Personally, I would just "keep it clean" and avoid this nonsense! E.g.:

i++;
Array = i;

Nice and simple. :)
 
Mike_R said:
...but it could be a C# rule (or even C/C++ rule).
I'm pretty sure in C++, arr[i++] = i++ is an ambiguous statement and can't be evaluated because the order of the evaluation of the i++ statements could go either way.

Mike_R said:
Personally, I would just "keep it clean" and avoid this nonsense!
Amen, brother. Think about what is actually going on for a second...
C#:
array[number++] = number++;
//is the same as...
array[number = number + 1] = (number = number + 1)
Well, assuming the new value of number is returned after/before (postfix/prefix ++) the assignment. In the words of Diesel, that's some ugly code!
 
Mike_R said:
Personally, I would just "keep it clean" and avoid this nonsense!
As far as my code goes, I would never write something like that. But I'm glad to discuss it.
Mike_R said:
Since the order of operations is arbitrary, I think that it's a bad idea to depend on it with calls like

array[i++] = i++
But the order of operations isn't arbatrary, albeit it appears ambiguous. The equals operator is a binary operator. When there is no other determining factor for precedence code is evaluated left-to-right, therefore the assignment target is evaluated first. If you write code such as:
C#:
int x = int.Parse(Console.ReadLine()) - int.Parse(Console.ReadLine());
which operand to the subtraction operator is evaluated first? The left, of course. Why? Because it has no more precedence than the right operand but it comes first. This is, as you put it, "set in stone." No, it's not usually smart to write code like that, but if you are looking to super-micro-optimize, some crazy code like that might eliminate a bytecode instruction or two.

Mike_R said:
I would prefer to read the above as the 'i++' occurring after the assignment is complete
The ++ operator is easy to misunderstand, even if you are familiar with it, because it is a quirky operator. That's exactly why it isn't in VB. It seems to express such a simple idea, "Add one to this variable," but in reality it says, "Load this variable, then store the loaded value plus one back to the variable but leave the original on the stack." The most intuitive way for me to think of the post-increment operator is that it increments the stored variable upon reading the value. Maybe there is no easy way to state that one... Regardless, this is, again, set in stone.

Also,
C#:
Array[i] = ++i;

// The above code would be behaviorally the same as:
Array[i] = i + 1;
i = i + 1;

// Also, the following code would produce the same exact result:
// (note that the ++ still finds itself between the 'i's)
Array[i++] = i;

// And this...
Array[i] = i++ + 1;

// Me thinks there are too many addition and subtraction operators.
The difference between ++i and i++ is that the value of the expression ++i will always be one greater than i++. Otherwise the two operators behave the same, even with regards to the order of operations.
 
Last edited:
Back
Top