I'm trying to understand how covariance works (in general, though my examples will be in C#) and what governs when a generic type can be covariant. Assume we have a class Animal
with subclasses Cat
and Dog
. I get why a read-only type such as IEnumerable<T>
is covariant, allowing this code to compile:
IEnumerable<Animal> initialAnimalEnumerable = new List<Cat> {new Cat() };
IEnumerable<Animal> addedAnimalEnumerable = initialAnimalEnumerable.Append(new Dog());
because the elements of the enumerable can only be treated as type Animal
; the information that they're Cats/Dogs specifically is lost. What I don't understand is why this can't apply with mutable collections such as List<T>
:
List<Animal> initialAnimalList = new List<Cat> {new Cat() }; // error CS0266: Cannot implicitly convert type 'List<Cat>' to 'List<Animal>'
initialAnimalList[0] = new Dog();
Explanations on questions like C# variance problem seem to assume that this would cause a problem, because we're trying to add a Dog
to a List<Cat>
...but why is it still treated as a List<Cat>
instead of a List<Animal>
?