Closures and Pass by Reference

What do you think the following code will do?

  1. Compile time error
  2. Run time error
  3. Work fine
static void Main(string[] args)
{
    int x = 10;
    int y = 5;
    Swap(ref x, ref y);
}

static void Swap(ref int x, ref int y)
{
    int temp = x;
    x = y;
    y = temp;
    Func<int> closure = () => x;
}

If you said 1. Compile time error then you would be correct.  The resulting error message is:

Cannot use ref or out parameter ‘x’ inside an anonymous method, lambda expression, or query expression

The reason for this is that although C# provides the ability to pass parameters by reference (as opposed to by value), it offers no way to assign to a variable by reference.

This ability exists in C++ :

int x = 5;
int & y = x;

Now y refers to the same variable location as x.

So, what does this all have to do with the original code?  As I described in my previous post Understanding Variable Capturing in C#, since we are using the variable x in a lambda expression (a.k.a. a closure) the C# compiler will rewrite the method so that it looks something like this:

class Capture
{
    public int x;
    public int Lambda()
    {
        return this.x;
    }
}

static void Swap(ref int x, ref int y)
{
    Capture capture = new Capture();
    capture.x = x;
    int temp = capture.x;
    capture.x = y;
    y = temp;
    Func<int> closure = () => capture.x;
}

Do you see the problem now?  On line 13 the ref parameter x is being assigned to the member variable x of the Capture class.  But since you can’t assign by reference this would change the semantics of the method.  The C# compiler is smart enough to know this, so it throws the error.  It won’t generate code that has different meaning than what the user intended.