Search code examples
scalacovariancecontravariance

Scala: arguments contravariant and return types are covariant why?


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?


Solution

  • 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.
    • you get a bonobo back from 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 animals

    But 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.