Quoting from the spec, section 4.5 Variance Annotations:
Variance annotations indicate how instances of parameterized types vary with respect
to subtyping (§3.5.2). A '+' variance indicates a covariant dependency, a '-'
variance indicates a contravariant dependency, and a missing variance indication
indicates an invariant dependency.
A variance annotation constrains the way the annotated type variable may appear
in the type or class which binds the type parameter. In a type definition
type T [tps] = S, or a type declaration type T [tps] >: L <: U type parameters
labeled +' must only appear in covariant position whereas type parameters labeled
'-' must only appear in contravariant position.
A type parameter is therefore by default considered to be invariant. You have to explicitly annotate the type parameter to be either co- or contravariant
if you want to use this. Also, it is perfectly legal to use variance annotations on a type parameter that is not used at all (although his may not be so useful).
For example:
scala> class A[+T, -S] {def myMethod(s: String) = println(s)}
defined class A
scala> class A2[T] {def myMethod(t: T) = println(t)}
defined class A2
scala> class A3[-T] {def myMethod(t: T) = println(t)}
defined class A3
scala> val a1 = new A2[Any]
a1: A2[Any] = A2@1cd1cea
scala> val a2: A2[Int] = a1
:6: error: type mismatch;
found : A2[Any]
required: A2[Int]
val a2: A2[Int] = new A2[Any]
scala> val a3 = new A3[Any]
a3: A3[Any] = A3@875dee
scala> val a4: A3[Int] = a3
a5: A3[Int] = A3@875dee
The variance annotation on class A3, which is contravariant in this example, makes that A3[Any] is considered to be a subtype of A3[Int],
making the assignment from instance a4 to a3 legal. This fails if you do not use the variance annotation.