I believe one can define covariance (at least, for objects) as \'the ability to use a value of a narrower (sub) type in place of a value of some wider (super) type\', and th
There are two separate ideas at work here. One is using subtyping to allow more specific arguments to be passed to a function (called subsumption). The other is how to check subtyping on functions themselves.
For type-checking the arguments to a function, you only have to check that the given arguments are subtypes of the declared argument types. The result also has to be a subtype of the declared type. This is where you actually check subtyping.
The contra/co-variance of the parameters & result only factor in when you want to check whether a given function type is a subtype of another function type. So if a parameter has type Function[A1, ... ,B]
, then the argument has to be a function type Function[C1, ..., D]
where A1 <: C1 ...
and D <: B
.
This reasoning isn't specific to Scala and applies to other statically-typed languages with subtyping.