Search code examples
c#covariancevaluetuple

What makes ValueTuple covariant?


This compiles correctly in C# 7.3 (Framework 4.8):

(string, string) s = ("a", "b");
(object, string) o = s;

I know that this is syntactic sugar for the following, which also compiles correctly:

ValueTuple<string, string> s = new ValueTuple<string, string>("a", "b");
ValueTuple<object, string> o = s;

So, it appears that ValueTuples can be assigned covariantly, which is awesome!

Unfortunately, I don't understand why: I was under the impression that C# only supported covariance on interfaces and delegates. ValueType is neither.

In fact, when I try to duplicate this feature with my own code, I fail:

struct MyValueTuple<A, B>
{
    public A Item1;
    public B Item2;

    public MyValueTuple(A item1, B item2)
    {
        Item1 = item1;
        Item2 = item2;
    }
}

...

MyValueTuple<string, string> s = new MyValueTuple<string, string>("a", "b");
MyValueTuple<object, string> o = s;
// ^ Cannot implicitly convert type 'MyValueTuple<string, string>' to 'MyValueTuple<object, string>'

So, why can ValueTuples be assigned covariantly, but MyValueTuples can't?


Solution

  • I believe what is actually happening here is a destructuring assignment. Tuple assignment will try to implicitly convert its components, and as it is possible to assign string to object, that is what happens here.

    The language supports assignment between tuple types that have the same number of elements, where each right-hand side element can be implicitly converted to its corresponding left-hand side element. Other conversions aren't considered for assignments.

    Source

    See it on sharplab.io