odd number of contravariant type constructors). The precise rule is that the return types of all methods in the interface must be valid covariantly and all the method parameter types must be valid contravariantly, where valid S-ly is defined as follows: Non-generic types (classes, structs, enums, etc.) are valid both co- and contravariantly. A type parameter is valid covariantly if it was not marked , and valid contravariantly if it was not marked . An array type is valid S-ly if is. (This is because C# has covariant arrays.) A generic type is valid S-ly if for each parameter , Ai is valid S-ly, and the ith parameter to is declared covariant, or Ai is valid (not S)-ly, and the ith parameter to is declared contravariant, or Ai is valid both covariantly and contravariantly, and the ith parameter to is declared invariant. As an example of how these rules apply, consider the interface. interface IList<T> { void Insert(int index, T item); IEnumerator<T> GetEnumerator(); } The parameter type of must be valid contravariantly, i.e. the type parameter must not be tagged . Similarly, the result type of must be valid covariantly, i.e. (since is a covariant interface) the type must be valid covariantly, i.e. the type parameter must not be tagged . This shows that the interface is not allowed to be marked either co- or contravariant. In the common case of a generic data structure such as , these restrictions mean that an parameter can only be used for methods getting data out of the structure, and an parameter can only be used for methods putting data into the structure, hence the choice of keywords. Data C# allows variance annotations on the parameters of interfaces, but not the parameters of classes. Because fields in C# classes are always mutable, variantly parameterized classes in C# would not be very useful. But languages which emphasize immutable data can make good use of covariant data types. For example, in all of Scala, Kotlin and OCaml the immutable list type is covariant: List[Cat] is a subtype of List[Animal]. Scala's rules for checking variance annotations are essentially the same as C#'s. However, there are some idioms that apply to immutable datastructures in particular. They are illustrated by the following (excerpt from the) definition of the List[A] class. sealed abstract class List[+A] extends AbstractSeq[A] { def head: A def tail: List[A] /** Adds an element at