it leaves the possibility of a run-time error that a stricter type system could have caught at compile-time. Also, it hurts performance because each write into an array requires an additional run-time check. With the addition of generics, Java and C# now offer ways to write this kind of polymorphic function without relying on covariance. The array comparison and shuffling functions can be given the parameterized types <T> boolean equalArrays(T[] a1, T[] a2); <T> void shuffleArray(T[] a); Alternatively, to enforce that a C# method accesses a collection in a read-only way, one can use the interface instead of passing it an array . Function types Languages with first-class functions have function types like "a function expecting a Cat and returning an Animal" (written in OCaml syntax or in C# syntax). Those languages also need to specify when one function type is a subtype of another—that is, when it is safe to use a function of one type in a context that expects a function of a different type. It is safe to substitute a function f for a function g if f accepts a more general type of argument and returns a more specific type than g. For example, functions of type , , and can be used wherever a was expected. (One can compare this to the robustness principle of communication: "be liberal in what you accept and conservative in what you produce.") The general rule is: if and . Using inference rule notation the same rule can be written as: In other words, the → type constructor is contravariant in the parameter (input) type and covariant in the return (output) type. This rule was first stated formally by John C. Reynolds, and further popularized in a paper by Luca Cardelli. When dealing with functions that take functions as arguments, this rule can be applied several times. For example, by applying the rule twice, we see that if . In other words, the type is covariant in the position of . For complicated types it can be confusing to mentally trace why a given type specialization is or isn't type-safe, but it is easy to calculate which positions are co- and contravariant: a position is covariant if it is on the left side of an even number of arrows applying to it. Inheritance in object-oriented languages When a subclass overrides a method in a superclass, the compiler must check