Just sharing some of my inconsequential lunch conversations with you... RSS  

Wednesday, January 20, 2010

Silly compiler season

I was revisiting an old geek post – a silly and inefficient way to swap integers avoiding an explicit temporary variable just for fun:

b = a + (a = b) - a;



On my first impression when reading this line of code I felt like simplifying the expression to something like:




b = (a = b);



Or even:



b = a - a + (a = b);



But I’m afraid it just doesn’t work. The original expression makes use of the order we are affecting the expression to get it done. Let me show what’s to IL:



    class Program
{
delegate void SwapDelegate (ref int a, ref int b);

const int MyConst1 = 123;
const int MyConst2 = 4567;

static void validate(string operation, SwapDelegate swapDelegate)
{
int a = MyConst1;
int b = MyConst2;
int oldA = a;
int oldB = b;

swapDelegate(ref a, ref b);

Console.WriteLine("{0} :: {1}", operation, oldA == b && oldB == a);
}

static void Main(string[] args)
{
// Swap: Ok
validate(
"b = a + (a = b) - a",
delegate(ref int a, ref int b)
{
b = a + (a = b) - a;
}
);


Reversing to IL we get:


validate("b = a + (a = b) - a", delegate (ref int a, ref int b) {
int CS$0$0000;
a = CS$0$0000 = b;
b = (a + CS$0$0000) - a;
});


As expected:




  1. the order is, as expected, relevant


  2. the temporary value is still there


  3. it is highly dependent on the order we write the expression – more, I’m not exactly sure the order we depend upon is guaranteed by the compiler


  4. on the imperative world, we should expect side-effects. And on some cases, we can even depend on them :)



 



Here are some results:



b = a + (a = b) - a   ::   True
b = a - a + (a = b) :: False
b = (a = b) :: False
b = a + (a = b) - b :: True
b = a - b + (a = b) :: True
b = (a = b) + a - b :: False
a = a + b - (b = a) :: True

No comments:

Development Catharsis :: Copyright 2006 Mário Romano