C# - Tuple arrays are mutable, but tuple lists are not. How do I get around this?

Viewed 1027

I have an array of value pairs I want to modify. I need to add and remove values from this array as well, so I used a list. When I tried to use a list, I encountered an error.

Error CS1612 - Cannot modify the return value of 'List<(int, float)>.this[int]' because it is not a variable

So I decided I would investigate. I tried using an array instead, and it... worked fine? The following code only throws an error on arr1[0].Item1 += 1;.

static void Main()
    {
        List<(int, float)> arr1 = new List<(int, float)>() { (0, 0) };
        (int, float)[] arr2 = new (int, float)[1];

        arr1[0].Item1 += 1; // This line
        arr2[0].Item1 += 1;
    }

Why are tuple arrays mutable, but lists are not? Is this because arrays are simple blocks of data you can modify easily, but lists have a lot of backend behind them that complicates things? Is there a simple way to get around this, or am I going to have to make my own custom class?

1 Answers

Why are tuple arrays mutable, but lists are not?

The list itself is mutable, but not in the way you're doing it. Note that this isn't anything specific to tuples - it's just the case for any mutable struct.

The list indexer getter returns a value (i.e. a copy of the tuple in your case) - so modifying that value wouldn't modify the copy in the list. The compiler is trying to avoid you making a change to a value that's about to be thrown away. Array access doesn't do that - arr2[0] refers to the variable within the array. (An array is effectively a collection of variables.)

If you want to mutate the list, you can have to fetch the tuple, mutate it, then put it back:

var tuple = arr1[0];
tuple.Item1++;
arr1[0] = tuple;

Note that this also explains why you can't use list access expressions as arguments for ref parameters, but you can do the equivalent for arrays:

public void Method(ref int x) => x++;

public void CallMethod()
{
    var list = new List<int> { 0 };
    var array = new int[] { 0 };
    Method(ref list[0]); // Error
    Method(ref array[0]); // Valid
}
Related