Covariance - An Example

You can often read that pameter Covariance is not type safe. In this post I am trying to construct a easy example why this is the case.

Covariance

Suppose the following simple declarations in Pseudo-Java Notation:

class Employee {
    public void doSomething(Employee e) {
    }
}

class Manager extends Employee {
    public void doSomething(Manager m) {
    }
}

This leads to the following UML class diagram:

UML class diagram

As you can clearly see, the parameters of the Employee.equals and Manager.equals method are covariant. This is why this code does not lead to the desired effects in programming languages like Java. Java prevents the Covariance by no overwriting but instead overloading the methods because it only supports parameter invariance.

For the following code I will suppose that the programing language supports Covariance and show why this makes the language type insafe.

Type Safety

Using the classes defined above we can write the following piece of code:

//Create a instance of Manager and Employee, no magic here
Manager manager = new Manager();
Employee employee = new Employee();

//Cast the Manager to a Employee, this is possible because
//the Manager class extends the Employee class
Employee managerAsEmployee = (Employee)employee;

//Now the problems occurs:
managerAsEmployee.doSomething(employee);

If you look at the last line, you will see the problem. Think about it, which method will be called, the one from Manager or the one from Employee?

It should be the Manager.doSomething method, because that is how inheritance of object is supposed to work (see the Liskov substitution principle), but as this method does not take a Employee (it only takes Manager) parameter, this will not work.

This is why languages like Java or C# do not support Covariance on parameters.

Further Reference