Why isn’t there generic variance for classes in C# 4.0?

Suppose you had a class C<T> that was covariant in T. What might its implementation look like? T has to be out only. That means that C<T> cannot have any method that takes a T, any property of type T with a setter, or any field of type T, because fields are logically the same as property setters; T goes in.

Pretty much the only useful thing you could build with a covariant class is something immutable as far as T is concerned. Now, I think it would be awesome to have covariant immutable lists and stacks and whatnot that were class types. But that feature is not so obviously awesome that it would clearly justify the massive expenditure in making the type system natively support covariant immutable class types.

A comment above asked for an example of where this would be useful. Consider the following sketch:

sealed class Stack<out T>
{
    private readonly T head;
    private readonly Stack<T> tail;
    public T Peek() { return head; }
    public Stack<T> Pop() { return tail; }
    public Stack(T head, Stack<T> tail)
    {
        this.tail = tail;
        this.head = head;
    }
}
static class StackExtensions
{
    public static Stack<T> Push<T>(this Stack<T> tail, T head) 
    {
        return new Stack<T>(head, tail);
    }
    public static bool IsEmpty<T>(this Stack<T> stack)
    {
        return stack == null;
    }
}

Suppose you had covariant classes. Now you can say

Stack<string> strings = null;
strings = strings.Push("hello");
strings = strings.Push("goodbye");
Stack<object> objects = strings;
objects = objects.Push(123);

And hey, we just pushed an integer onto a stack of strings, but everything worked out just fine! There’s no reason why this couldn’t be typesafe. An operation which would violate type safety on a mutable data structure can be safely covariant on an immutable data structure.

Leave a Comment