In the FP in Scala course, Martin mentions, the arguments are "contravariant" while the return types are "covariant". I don't think I understood that completely - can someone help with this one?
Assume Bonobo
extends Animal
and you have a function foo
of type Animal => Bonobo
. In some other place you have a variable bar
of type Bonobo => Animal
. Should you be allowed to assign foo
to bar
? Sure:
foo
expects just an animal as argument (which is "too wide" or "too general" compared to the expected argument type Bonobo
of bar
, hence contravariant), but it has no problem processing a bonobo.foo
(which is "too narrow" or "too special" compared to the expected return type Animal
of bar
, hence covariant), but this is fine, as the caller of bar
expects to deal with all kinds of animalsBut you can't turn the example around, you can't assign a Bonobo => Animal
function where an Animal => Bonobo
function is expected, as the argument doesn't fit (it might get an animal that isn't a bonobo), and the return type is wrong either (you need a bonobo back, but get an animal, which could be something different).
This is true for all function-like things (e.g. methods): It doesn't matter if argument types are more general and return types are be more special than expected. "Contravariant" and "covariant" is just fancy terminology for this simple fact.