A plus or minus sign in front of a type constructor argument means that values of that type appear in covariant (+) or contravariant (-) position. A covariant position means the type only ever occurs as "output" or return type, as is the case with List. Then a List[A] is a subtype of a List[B] if A <: B, if A is a sub-type of B:
trait Animal { def food: String } case class Dog(name: String) extends Animal { def food = "all" } def test(xs: List[Animal]) = xs.map(_.food) test(List(Dog("Jussi")))
Here you can pass a List[Dog] for a List[Animal] because List[Dog] <: List[Animal].
Contravariance is the opposite - the type only occurs as input. For example Function1[A, Out] <: Function1[B, Out] if A >: B, if A is a super-type of B.
def test(fun: Dog => String): String = fun(Dog("Jussi")) test { x: Animal => x.food }
Here you can pass a Animal => String for a Dog => String because the former is sub-type of the latter.
The variance annotation + or - only ever occurs in the definition of the type, so in the definition of List[+A], not anywhere else where List is used, e.g. as type ascription or in the extends clause, because the variance cannot change once it's defined. This is called definition-site variance.
Because Nothing is the bottom type in Scala, a type that is the sub-type of any other type, we can thus have the convenient object Nil extends List[Nothing], and thereby Nil becoming the sub-type of List[A] for any possible A. Whenever you need a list, no matter what the element type, you can use Nil.
Mr. V., a few times before understanding it. So don't be discouraged.