Tutorial by Examples

The + symbol marks a type parameter as covariant - here we say that "Producer is covariant on A": trait Producer[+A] { def produce: A } A covariant type parameter can be thought of as an "output" type. Marking A as covariant asserts that Producer[X] <: Producer[Y] prov...
By default all type parameters are invariant - given trait A[B], we say that "A is invariant on B". This means that given two parametrizations A[Cat] and A[Animal], we assert no sub/superclass relationship between these two types - it does not hold that A[Cat] <: A[Animal] nor that A[Ca...
The - symbol marks a type parameter as contravariant - here we say that "Handler is contravariant on A": trait Handler[-A] { def handle(a: A): Unit } A contravariant type parameter can be thought of as an "input" type. Marking A as contravariant asserts that Handler[X] &l...
Because collections are typically covariant in their element type*, a collection of a subtype may be passed where a super type is expected: trait Animal { def name: String } case class Dog(name: String) extends Animal object Animal { def printAnimalNames(animals: Seq[Animal]) = { anima...
There is also a way to have a single method accept a covariant argument, instead of having the whole trait covariant. This may be necessary because you would like to use T in a contravariant position, but still have it covariant. trait LocalVariance[T]{ /// ??? throws a NotImplementedError de...

Page 1 of 1