Yes! Another of this question, and yes i already read alot of this questions in stackoverflow and still don't understand this concept and it's application.
So, i'm i new comer to Scala, and like many people i still didn't get the concept of Contravariance, i'm reading the Programming Scala, 2nd Edition, and on page 283 starts the explanation of co and contravariance with the following example:
gives the hierarchy:
class CSuper { def msuper() = println("CSuper") }
class C extends CSuper { def m() = println("C") }
class CSub extends C { def msub() = println("CSub") }
then there is a function and some examples of use:
var f: C => C = (c: C) => new C
f = (c: CSuper) => new CSub
f = (c: CSuper) => new C
f = (c: C) => new CSub
f = (c: CSub) => new CSuper // COMPILATION ERROR!
Thinking in java i know that the last expression won't compile because CSuper is a Supertype of CSub.
What i don't understand is what means a type, in this case the Function1[-C,+C], is contravariant in the first parameter?
The book says that for contravariance is when where X[String] is a supertype of X[Any], for some type X.
The co / contravariance is just appliable in the subclasses of the parameterized types, i mean since we are using a Function1, the variance just applies to subtypes of Function1, would be it?
And how does it actually works, and when should i use / need it?
if T’ is a subclass of T, is Container[T’] considered a subclass of Container[T]?
[+T]
covariant: C[T’] is a subclass of C[T],
[-T]
contravariant: C[T] is a subclass of C[T’]
Function1
is defined as trait Function1[-T1, +R]
, so parameters are contravariant and result type is covariant.
That means, that functions, which arguments are supertypes of argument type of given function, and which result type is subtype of result type of given function is itself subtype of given function.
In your example, as you are assigning different function declarations to f
of type C => C
, only assigning of valid subtypes will compile.
Namely, only these function declarations are valid subtypes of C => C
:
var f: C => C = (c: C) => new C
f = (c: C) => new C
f = (c: C) => new CSub
f = (c: CSuper) => new C
f = (c: CSuper) => new CSub
Everything else is either supertype of C => C
and can't be assigned to f
or unrelated type.