Covariance And Contravariance - A Simple Guide
Written by Mike James   
Friday, 20 November 2020
Article Index
Covariance And Contravariance - A Simple Guide
Object Hierarchies
Why Bother?

What's the point?

Now you understand the idea of covariance and contravariance you might be wondering what the point is?

The answer is that it is all a matter of when a language, or a language implementation, should, or could, allow automatic type conversion.

As array construction is covariant, if T(B) constructs an array of type B, it is fairly safe to treat an array of B as being an array of A without needing an explicit type conversion.

In many languages you can indeed write:

string[] x=new string[];
object[] y=a;

without the need for a cast and this is because object>string implies object[]>string[]. 

For a more involved example consider the C# delegate.

A delegate is a type that can wrap a function with a specific signature. A delegate accepts a function as input parameter and returns a delegate type that wraps it.

Consider a delegate

delegate Mydelegate(functionB);

and two functions which only differ in the type of their input parameter then A>B implies by contravariance:

functionA(A param)<functionB(B param);

Hence functionA can be used anywhere functionB can and so it should be safe to use Mydelegate to wrap an instance of a function that has parameters that are less derived than it.

By a similar argument a delegate:

delegate Mydelegate(A function);

which wraps a function which returns an A should be quite safe wrapping a function that returns a B as A>B implies by covariance that A function>B function and so you can use a B function anywhere you can use an A function. Thus delegates are covariance in the return parameter of the function they wrap and so can safely wrap a function that returns a more derived result.

Is it worth it?

Is it worth introducing what appear to be complex ideas like covariance and contravariance?

In practical work probably not as the whole thing is usually simple enough to work out from first principles.

For example, can an array of strings be used in place of an array of objects?

Well yes obviously as a string is just an object with additional properties and methods so it can always be treated as an object.

So if you want to just think about type conversion and substitution rules from first principles that's fine. If you want to dress the idea up in the terms covariance and contravariance that's fine too.

However, the academic terms do have the disadvantage that it's easy to miss practical concerns.

Languages have to be pragmatic and this means they don't always obey the substitution principle.

For example a double can always be used where an integer can be used - e.g. write 1.0  in place of 1 but in practice it it rare for a language to define a double as a derived type of int.

For another example, consider the array of string types. If this is cast to an array of object types then this works for all read access but write access often fails. For example, try

string[] mystring=new string[10];
object[] myobject=mystring;

in most languages this will fail because the underlying type of the object element is string and not object but by the substitution principle it should work. In this case it is a result of inheritance not being implemented fully, i.e. an array of strings isn't really an array of objects with some additional properties.

In practice programming is more complicated and messy that pure theory allows.

Look out for a follow-on article that explains covariance and contravariance in C# in more detail.


Related Articles

Strong typing

Casting – the escape from strong typing

Introduction to Delegates

Barbara Liskov Admitted to National Inventors Hall of Fame       


To be informed about new articles on I Programmer, sign up for our weekly newsletter, subscribe to the RSS feed and follow us on Twitter, Facebook or Linkedin.



Is Rust Safe?

Rust is our great hope for the future. Even if you are not using it you probably have heard of it and believe it is a safer language than C or C++. But is it really?

TypeScript 5.5 Adds ECMAScript Set Support

TypeScript 5.5 is now available as a release candidate. This version adds support for the proposed ECMAScript Set methods, as well as inferred type predicates and the ability to narrow expressions for [ ... ]

More News

C book



or email your comment to:





Last Updated ( Friday, 20 November 2020 )