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] provided that X <: Y. For example, a Producer[Cat] is a valid Producer[Animal], as all produced cats are also valid animals.
A covariant type parameter cannot appear in contravariant (input) position. The following example will not compile as we are asserting that Co[Cat] <: Co[Animal], but Co[Cat] has def handle(a: Cat): Unit which cannot handle any Animal as required by Co[Animal]!
trait Co[+A] {
def produce: A
def handle(a: A): Unit
}
One approach to dealing with this restriction is to use type parameters bounded by the covariant type parameter. In the following example, we know that B is a supertype of A. Therefore given Option[X] <: Option[Y] for X <: Y, we know that Option[X]'s def getOrElse[B >: X](b: => B): B can accept any supertype of X - which includes the supertypes of Y as required by Option[Y]:
trait Option[+A] {
def getOrElse[B >: A](b: => B): B
}