jane doe - 1 year ago 130
C# Question

# Difference between Covariance & Contra-variance

I am having trouble understanding the difference between covariance and contravariance.

The question is "what is the difference between covariance and contravariance?"

Covariance and contravariance are properties of a mapping function that associates one member of a set with another. More specifically, a mapping can be covariant or contravariant with respect to a relation on that set.

Consider the following two subsets of the set of all C# types. First:

``````{ Animal,
Tiger,
Fruit,
Banana }.
``````

And second, this clearly related set:

``````{ IEnumerable<Animal>,
IEnumerable<Tiger>,
IEnumerable<Fruit>,
IEnumerable<Banana> }
``````

There is a mapping operation from the first set to the second set. That is, for each T in the first set, the corresponding type in the second set is `IEnumerable<T>`. Or, in short form, the mapping is `T → IE<T>`.

With me so far?

Now let's consider a relation. There is an assignment compatibility relationship between pairs of types in the first set. A value of type `Tiger` can be assigned to a variable of type `Animal`, so these types are said to be "assignment compatible". Let's write "a value of type `X` can be assigned to a variable of type `Y`" in a shorter form: `X ⇒ Y`. So in our first subset, here are all the assignment compatibility relationships:

``````Tiger  ⇒ Tiger
Tiger  ⇒ Animal
Animal ⇒ Animal
Banana ⇒ Banana
Banana ⇒ Fruit
Fruit  ⇒ Fruit
``````

In C# 4, which supports covariant assignment compatibility of certain interfaces, there is an assignment compatibility relationship between pairs of types in the second set:

``````IE<Tiger>  ⇒ IE<Tiger>
IE<Tiger>  ⇒ IE<Animal>
IE<Animal> ⇒ IE<Animal>
IE<Banana> ⇒ IE<Banana>
IE<Banana> ⇒ IE<Fruit>
IE<Fruit>  ⇒ IE<Fruit>
``````

Notice that the mapping `T → IE<T>` preserves the existence and direction of assignment compatibility. That is, if `X ⇒ Y`, then it is also true that `IE<X> ⇒ IE<Y>`.

A mapping which has this property with respect to a particular relation is called a "covariant mapping". This should make sense: a sequence of Tigers can be used where a sequence of Animals is needed, but the opposite is not true. A sequence of animals cannot necessarily be used where a sequence of Tigers is needed.

That's covariance. Now consider this subset of the set of all types:

``````{ IComparable<Tiger>,
IComparable<Animal>,
IComparable<Fruit>,
IComparable<Banana> }
``````

now we have the mapping from the first set to the third set `T → IC<T>`.

In C# 4:

``````IC<Tiger>  ⇒ IC<Tiger>
IC<Animal> ⇒ IC<Tiger>     Backwards!
IC<Animal> ⇒ IC<Animal>
IC<Banana> ⇒ IC<Banana>
IC<Fruit>  ⇒ IC<Banana>     Backwards!
IC<Fruit>  ⇒ IC<Fruit>
``````

That is, the mapping `T → IC<T>` has preserved the existence but reversed the direction of assignment compatibility. That is, if `X ⇒ Y`, then `IC<X> ⇐ IC<Y>`.

A mapping which preserves but reverses a relation is called a contravariant mapping.

Again, this should be clearly correct. A device which can compare two Animals can also compare two Tigers, but a device which can compare two Tigers cannot necessarily compare any two Animals.

So that's the difference between covariance and contravariance in C# 4. Covariance preserves the direction of assignability. Contravariance reverses it.

Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download