views:

330

answers:

3

I wonder if there's any way something like this would be possible for value types...

public static class ExtensionMethods {
    public static void SetTo(this Boolean source, params Boolean[] bools) {
  for (int i = 0; i < bools.Length; i++) {
   bools[i] = source;
  }
 }
}

then this would be possible:

Boolean a = true, b, c = true, d = true, e;
b.SetTo(a, c, d, e);

Of course, this does not work because the bools are a value type so they are passed into the function as a value, not as a reference.

Other than wrapping the value types into reference types (by creating another class), is there any way to pass a variable into function by the reference (ref) while using params modifier?

A: 

This would not be possible even if bools were reference types. While a class is a reference type, the variable in the Boolean[] is still a value, it's just that the value is a reference. Assigning the value of the reference just changes the value of that particular variable. The concept of an array of ref variables doesn't make sense (as arrays are, by their nature, a series of values).

Adam Robinson
Arrays are NOT a series of values. Arrays are a series of *variables*. The reason why we disallow having arrays of references to variables is not that doing so is illogical; it is perfectly logical to do so. It's that doing so prevents us from optimizing deallocations of local variables of value type by moving the stack pointer. *That* is why you cannot store a reference to a variable in a field or array slot.
Eric Lippert
@Eric: Obviously you're right; I meant to say that arrays are a series of variables that are contiguously allocated, so being able to specify an arbitrary list of variable references to constitute an array wouldn't make sense.
Adam Robinson
+1  A: 

There isn't really a way. You could do something like this:

public static void Main(string[] args)
{
    BooleanWrapper a = true, b = true, c = true, d = true, e = new BooleanWrapper();
    b.SetTo(a, c, d, e);
}

public static void SetTo(this BooleanWrapper sourceWrapper, params BooleanWrapper[] wrappers)
{
    foreach (var w in wrappers)
        w.Value = sourceWrapper.Value;
}

public class BooleanWrapper
{
    public BooleanWrapper() { }

    public BooleanWrapper(Boolean value)
    {
        Value = value;
    }

    public Boolean Value { get; set; }

    public static implicit operator BooleanWrapper(Boolean value)
    {
        return new BooleanWrapper(value);
    }
}

But then again how is that any better than just doing this:

public static void Main(string[] args)
{
    Boolean[] bools = new Boolean[5];
    bools.SetTo(bools[1]); // Note I changed the order of arguments. I think this makes more sense.
}

public static void SetTo(this Boolean[] bools, Boolean value)
{
    for(int i = 0; i < bools.Length; i++)
        bools[i] = value;
}

After all, an array is a sequence of variables. If you need something that behaves like a sequence of variables, use an array.

Joren
He could do this but with the nullable-versions - `bool?` or `Nullable<bool>`.
Daniel A. White
No, `Nullable`s are copied when passing (in stead of passing a reference) and you can't mutate their value either.
Joren
+7  A: 

This is not possible. To explain why, first read my essay on why it is that we optimize deallocation of local variables of value type by putting them on the stack:

http://blogs.msdn.com/ericlippert/archive/2009/05/04/the-stack-is-an-implementation-detail-part-two.aspx

Now that you understand that, it should be clear why you cannot store a "ref bool" in an array. If you could, then you could have an array which survives longer than the stack variable being referenced. We have two choices: either allow this, and produce programs which crash and die horribly if you get it wrong -- this is the choice made by the designers of C. Or, disallow it, and have a system which is less flexible but more safe. We chose the latter.

But let's think about this a little deeper. If what you want is to pass around "thing which allows me to set a variable", we have that. That's just a delegate:

static void DoStuff<T>(this T thing, params Action<T> actions)
{
    foreach(var action in actions) action(thing);
}
...
bool b = whatever;
b.DoStuff(x=>{q = x;}, x=>{r = x;} );

Make sense?

Eric Lippert