Assignment Compatibility, Covariance and Contravariance

The terms covariance and contravariance enable implicit references to conversion of array type, delegate type, and generic type arguments. Covariance preserves assignment compatibility and contravariance reverses it.

Assignment Compatibility

If we have a string name "avinash", programmatically we can declare it as:
string strVal = "avinash";

We can assign a strVal in a more derived type to an object of less derived type. Like:

object obj = str;

Covariance

We can use IEnumerable<string> in places where IEnumerable<object> is expected. It converts a larger data type to a smaller one (for exzmple Long to Int). We can understand it as in the following.

An object that is instantiated with a more derived type is assigned to an object with a less derived type.

IEnumerable<string> stringVal = new List<string>();
IEnumerable<object> obj = stringVal;

In this case assignment compatibility is preserved.

Contravariance

We can pass IComparable<object> as an argument of a method taking IComparable<string>. It converts a smaller data type to larger one (for exzmple Int to Float).

Suppose we have a method in our class as in the following:

Private void SetObjectField(object o){ }

An object that is instantiated with a less derived type is assigned to a more derived type.

 Action<object> objAction = SetObject;
 Action<
string> obj = actObject;


In this case assignment compatibility is also reversed.


Mathematical Understanding of Covariance and Contravariance

Now, let's try to understand covariance and contravariance mathematically:

First, let's understand Projection. Projection is a simple function that takes a single integer and returns a single integer value as is explained in the following example:

x -> x + x

In this example we call it D for double.

Let's consider another example:

y -> 0-y

Here, we call it N as Negation.

Hence, we have two interesting scenarios. At first, we will discuss D (Double):

(a <= b) = (D(a) <= D(b)) // <= less than and equal to

If a is less than b then twice of a will be less than twice of b. If a is equal to b then twice of a will be equal to twice of b, and if a is greater than b then twice of a will be greater than twice of b. So projection D preserves the direction of the size.

Now to discuss N (negation):

(a <= y) = (N(a) <= N(b)) // <= less than and equal to

See:

1 <=2 is true, but
-1 <= -2 is false.

Since this is negation, the reverse is always true. The projection N reverses the direction of the size.

Clearly, we can say mathematically that D is a "Covariance" since it preserves the direction of the size. Similarly, the Projection N is "Contravariance" since it reverses the ordering direction.

Any recommendation and feedback will be highly appreciated. I hope this article proves useful for you. Thanks for reading!!!