Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Evaluation of expressions within an if statement

Tags:

syntax

c#

While refactoring some code written by someone else, I've come across some weirdness that I don't understand, and I'm hoping someone can explain why it happens.

if (mystring.Length != (mystring = mystring.Replace("!#", replacement)).Length)
{
    i = 1;
}
else if (mystring.Length != (mystring = mystring.Replace("#", replacement)).Length)
{
    i = -1;
}

What I thought would happen here would be that as brackets have the highest precedence, the assignment inside the brackets would happen first and none of the code inside the if and else if blocks would be executed. Here is what I thought this code was effectively doing:

mystring = mystring.Replace("!#", replacement);
if (mystring.Length != mystring.Length)
{
    i = 1;
}
else
{
    mystring = mystring.Replace("#", replacement);
    if (mystring.Length != mystring.Length)
    {
        i = -1;
    }
}

I thought that the only thing that would happen would be the changes to mystring, as the assignment would be made before the comparison. Testing this out has shown that what happens is actually closer to this:

string temp1 = mystring.Replace("!#", replacement);
string temp2 = mystring.Replace("#", replacement);
if (mystring.Length != temp1.Length)
{
    i = 1;
}
else if (mystring.Length != temp2.Length)
{
    i = -1;
}
if (i == 1)
{
    mystring = temp1;
}
else
{
    mystring = temp2;
}

If that isn't clear, what I think is happening is that the assignment to mystring is being made after the truth of the expression is evaluated, rather than as the first part of evaluating that expression as I had thought. My third piece of code might not get that across very well but I can't think of a better way to express it!

In short:

  1. Will my third code snippet always give the same result as the first?
  2. Why doesn't the first code snippet do the same thing as the second?
like image 938
phoebelmurphy Avatar asked Sep 17 '13 16:09

phoebelmurphy


1 Answers

Precedence isn't about ordering operations - it's about binding operations together. The execution order is always left to right. So for example, if you write:

int a = x * (y / z);

then x is still evaluated before y / z.

So in this expression:

if (mystring.Length != (mystring = mystring.Replace("!#", replacement)).Length)

we have:

  • Evaluate mystring.Length (we'll call this value x)
  • Evaluate (mystring = mystring.Replace("!#", replacement)).Length
    • Evaluate mystring.Replace("!#", replacement)
    • Assign the result to mystring
    • Take the length (we'll call this value y)
  • Compare x and y

As is clear from the confusion, this code is horrible - I'm glad you're refactoring it away from its current form.

like image 161
Jon Skeet Avatar answered Oct 13 '22 11:10

Jon Skeet