left-over parameters to be at least as general. Using the previous terminology, types used for runtime method selection are covariant while types not used for runtime method selection of the method are contravariant. Conventional single-dispatch languages like Java also obey this rule: only one argument is used for method selection (the receiver object, passed along to a method as the hidden argument ), and indeed the type of is more specialized inside overriding methods than in the superclass. Castagna suggests that examples where covariant parameter types are superior (particularly, binary methods) should be handled using multiple dispatch; which is naturally covariant. However, most programming languages do not support multiple dispatch. Summary of variance and inheritance The following table summarizes the rules for overriding methods in the languages discussed above. Generic types In programming languages that support generics (a.k.a. parametric polymorphism), the programmer can extend the type system with new constructors. For example, a C# interface like makes it possible to construct new types like or . The question then arises what the variance of these type constructors should be. There are two main approaches. In languages with declaration-site variance annotations (e.g., C#), the programmer annotates the definition of a generic type with the intended variance of its type parameters. With use-site variance annotations (e.g., Java), the programmer instead annotates the places where a generic type is instantiated. Declaration-site variance annotations The most popular languages with declaration-site variance annotations are C# and Kotlin (using the keywords and ), and Scala and OCaml (using the keywords and ). C# only allows variance annotations for interface types, while Kotlin, Scala and OCaml allow them for both interface types and concrete data types. Interfaces In C#, each type parameter of a generic interface can be marked covariant (), contravariant (), or invariant (no annotation). For example, we can define an interface of read-only iterators, and declare it to be covariant (out) in its type parameter. interface IEnumerator<out T> { T Current { get; } bool MoveNext(); } With this declaration, will be treated as covariant in its type parameter, e.g. is a subtype of . The type checker enforces that each method declaration in an interface only mentions the type parameters in a way consistent with the / annotations. That is, a parameter that was declared covariant must not occur in any contravariant positions (where a position is contravariant if it occurs under an