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:
- the order is, as expected, relevant
- the temporary value is still there
- 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
- 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:
Post a Comment