When is assignment to a ref argument effective in C#?

Suppose a method is changing the value of an argument passed by reference. Is the effect of such operation immediately visible across the application or only after the method returns?

Below an example when this is significant:

int x = 0;
void Foo(ref int y)
{
    ++y;
    Console.WriteLine(x);
}
Foo(ref x);

It can be run in C# Pad under http://csharppad.com/gist/915318e2cc0da2c2533dfa7983119869

The function Foo has access to the variable x because it is in the same scope and also it just so happens to receive a reference to it at call site. If the effect of ++y is immediate, the output should be 1, but I can imagine a compiler to generate code that, for example, stores the local value in a register and dumps to memory at some later time before return. Does the language specification ensure the output to be 1 or does it allow the jitter to optimize, making the output implementation dependent?

Jon Skeet
people
quotationmark

Is the effect of such operation immediately visible across the application or only after the method returns?

It's immediately visible - because basically, what you end up passing is the variable itself, not the variable's value. You're modifying the exact same storage location.

Indeed, you can see this within the same same method:

using System;

class Test
{
    static void Main(string[] args)
    {
        int a = 10;
        Foo(ref a, ref a);
    }

    static void Foo(ref int x, ref int y)
    {
        x = 2;
        Console.WriteLine(y); // Prints 2, because x and y share a storage location
    }
}

This is in the C# 5 spec in section 5.1.5:

A reference parameter does not create a new storage location. Instead, a reference parameter represents the same storage location as the variable given as the argument in the function member or anonymous function invocation. Thus, the value of a reference parameter is always the same as the underlying variable.

The same is true in reverse, by the way - if the value of the underlying variable is changed in some other way, that change will be visible in the method. Example using a delegate to change the value:

using System;

class Test
{
    static void Main(string[] args)
    {
        int a = 10;
        Foo(ref a, () => a++);
    }

    static void Foo(ref int x, Action action)
    {
        Console.WriteLine(x); // 10
        action();             // Changes the value of a
        Console.WriteLine(x); // 11
        x = 5;
        action();
        Console.WriteLine(x); // 6
    }
}

people

See more on this question at Stackoverflow