While merrily browsing the Internet and reading technical articles about programming, you may encounter the terms of "covariance" and "contravariance." These sound spooky enough to make you consider closing the tab and forgetting all about it, as if it were a bad dream. It doesn't have to be that way!
These two terms are actually abstract mathematical concepts that are used in probability theory, statistics, theoretical physics, category theory and (you guessed it!) computer science. Each aforementioned field has a certain definition regarding what covariance / contravariance is. Each definition may or may not have a degree of similarity to the other definitions in the other fields.
During this talk, we'll try to make sense of these things, together. We'll lightly touch upon what covariance and contravariance means in a couple of applied mathematical scenarios (Don't worry, we won't be talking about functors!). Then, we'll see how these concepts are used to describe subtyping relationships in programming languages such as Java and C#. There will be code examples, of course!
24. Integer is a subtype of Number
Integer i = 1;
Number n = i;
Number < Integer
Number ← Integer
< means “is a subtype of”
← means “can be assigned to”
*read from right to the left
25. Integer[] is a subtype of Number[]
Integer[] ints = {1, 2, 3};
Number[] nums = ints;
Number[] < Integer[]
Number[] ← Integer[]
< means “is a subtype of”
← means “can be assigned to”
*read from right to the left
27. ArrayList<Integer> ints = new ArrayList<Integer>();
ArrayList<? extends Number> nums = ints;
Number ← Integer
Number[] ← Integer[]
<? extends Number> ← <Integer>
Can be assigned in the same order.
This generic list is covariant.
A B← means “B can be assigned to A”
28. ArrayList<Object> objs = new ArrayList<Object>();
ArrayList<? super Number> nums = objs;
Object ← Number
Object[] ← Number[]
<Object> → <? super Number>
Can be assigned in the reverse order.
This generic list is contravariant.
A B← means “B can be assigned to A”
37. class A {
Object getSomething(){}
}
class B extends A {
String getSomething() {}
}
Covariance because it returns a String
which extends Object (more derived)
38. class A {
void doSomething(String param){}
}
class B extends A {
void doSomething(Object param){}
}
Contravariance because it takes an
Object which is a super class of String
(less derived)