Question

I was reading up on covariance and contravariance today and I came across a post on stack exchange where Jon Skeet was explaining invariance at the class level. He used an example of fruit and why allowing covariance at that level would be a bad thing:

//Bad
List<Banana> bunchOfBananas = new List<Banana>();
// This would be valid if List<T> were covariant in T
List<Fruit> fruitBowl = bunchOfBananas;
fruitBowl.Add(new Apple());
Banana banana = bunchOfBananas[0];

So, how does this account for having a list of Fruit that you would add instances of class that inherit from Fruit? For example:

//Good
List<Fruit> fruitBowl = new List<Fruit>();
fruitBowl.Add(new Apple());
fruitBowl.Add(new Banana());

I've done this in the past and it always behaves as expected. Why doesn't the CLR look at the type of fruitBowl? Is it because you are setting the value of your fruitBowl to a list of Bananas first which is covariant to a list of Fruit and then trying to add an Apple to a collection whose type is really List<Banana>?

Thanks to Matt below. It helps to remember that you're dealing with reference types. Downvote this forever.

Was it helpful?

Solution

I think what you are missing is that when you do in your first example:

List<Fruit> fruitBowl = bunchOfBananas;

You are not making a copy of bunchOfBananas into a List<Fruit>. Instead, you are creating a reference to a bunch of bananas, and that reference could be used to add any kind of fruit.

Thus when you do:

fruitBowl.Add(new Apple());

you would not be adding an apple to a list of fruit; you'd be adding an apple to the List<Banana> bunchOfBananas, which is clearly A Bad Thing.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top