Covariance


In [5]:
sealed trait MyOption[A]
case class MySome[A](get: A) extends MyOption[A]
case class MyNone[A]() extends MyOption[A]


defined trait MyOption
defined class MySome
defined class MyNone

In [6]:
def f(a: MyOption[Any]) = a


defined function f

In [7]:
f(MySome[Any](1))


res6: MyOption[Any] = MySome(1)

In [6]:
f(MySome[Int](1))


Main.scala:27: type mismatch;
 found   : cmd6.this.$ref$cmd4.MySome[Int]
 required: cmd5.INSTANCE.$ref$cmd4.MyOption[Any]
Note: Int <: Any, but trait MyOption is invariant in type A.
You may wish to define A as +A instead. (SLS 4.5)
f(MySome[Int](1))
             ^

In [8]:
sealed trait MyOption2[+A]
case class MySome2[A](get: A) extends MyOption2[A]
case class MyNone2[A]() extends MyOption2[A]


defined trait MyOption2
defined class MySome2
defined class MyNone2

In [9]:
def f(a: MyOption2[Any]) = a


defined function f

In [10]:
f(MySome2[Int](1))


res9: MyOption2[Any] = MySome2(1)

Contravariance


In [11]:
def toS(a: Any) = a.toString


defined function toS

In [12]:
toS(List(1,2,3))


res11: String = "List(1, 2, 3)"

In [13]:
def f(a: String => String, s: String) = a(s)


defined function f

In [14]:
// This works even though f is String => String
f(toS, "abc")


res13: String = "abc"

To understand why take a look at Function1:

trait Function1[-T1, +R] extends AnyRef

which is contravariant in input.

Acknowledgement

Thanks to @deaktator for explaining these to me