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>?