In Scala for the Impatient It is said that
functions are contra-variant in their arguments and covariant in their result type
This is straightforward and easy to understand ,however in the same topic it says
However inside a function parameter ,the variance flips- its parameters are covariant
and it takes the example of foldLeft method of Iterator as :
def foldLeft[B](z : B)(op : (B, A) => B) : B
I am not getting it clearly what it says.
I tried some of blogs as
http://blog.kamkor.me/Covariance-And-Contravariance-In-Scala/
http://blogs.atlassian.com/2013/01/covariance-and-contravariance-in-scala/
But didn't get clear understanding.
A function is always contravariant in its argument type and covariant in its return type e.g.
trait Function1[-T1, +R] extends AnyRef
trait Function2[-T1, -T2, +R] extends AnyRef
Here, T1
,T2
, ..., T
n (where n <= 22
) are arguments and R
is the return type.
In higher order functions (functions that take function as argument), an argument can have the type parameter that is passed into the function
e.g.
foldLeft
in trait Iterable
Iterable
is declared as
trait Iterable[+A] extends AnyRef
and foldLeft
is decalred as
def foldLeft[B](z : B)(op : (B, A) => B) : B
Since A
is declared covariant, it can be used as the return type. But here it is instead an argument type due to
trait Function2[-T1, -T2, +R] extends AnyRef
because op : (B, A) => B
is the literal type of Function2
.
The key to this is trait Function2
is contravariant in its argument type.
Hence covariance type is appearing in method argument due to
trait Function2 is contravariant in its argument type
This is called variance flip:
That's why invariant may appear at any position (covariance/contravariance)