29 maggio
Contravariance, Covariance, and Generics
The common question is: what the hell is contravariance and covariance?
Ok so you are familiar with casting right? In C# we can do this:
public class Animal { }
public class Monkey : Animal { }
...
Animal a = new Monkey();
((Monkey)a).FlingCrap();
We can also do this:
public void MoveWest(Animal a) { }
...
MoveWest(new Monkey());
Because the 'MoveWest' method accepts the narrowing type 'Animal' it is said to support 'Contravariance'. If the C# compiler forced us to only pass exact types, then it would be considered 'invariant'. Likewise C# methods support covariance, in that we can return a narrower type and cast the resulting instance to its correct form.
There are parts of the .Net framework however that aren't so flexible. In this case, I'm talking about generics.
Consider this for example:
List<Monkey> monkeys = new List<Monkey>();
monkeys .Add(new Monkey());
List<Animal> animals = monkeys;
Unfortunately this does not compile. We get the following warning:
Cannot implicitly convert type 'System.Collections.Generic.List<FeaturesCsharp2.Monkey>' to 'System.Collections.Generic.List<FeaturesCsharp2.Animal>'
Why is this? Monkey inherits Animal, so the list conversion is perfectly safe. Well this is one case of invariance. But here's the kicker: word on the street is that the CLR actually supports contravariance of generic lists; its just the C# compiler that doesn't!