/* Typed languages are sometimes disliked by programmers because they impose contraints on programs that are sometimes unnecessary. A typed language will error on the side of safety. The following advanced feature will attempt to alleviate the problem by allowing the class-interface relationship to be more flexible. The terms "covariance" and "contravariance" come from a branch of advanced mathematics called category theory. But it's possible to understand it in much simpler, set-theoretic terms. A function with domain set A and codomain (range) B must map *every* element of A to *some* element in B. Suppose that set A1 is a subset of A2 and that B1 is a subset of B2. Suppose you are asked to provide a function from set A1 into set B2. If you're asked to provide a function from A to B, can you use a function from A2 into set B1 The answer is YES, because since A1 is a subset of A2, every element of A1 will also be in the domain of your function. And since every element of B1 is a subset of B2, every value that your function maps to is also in B2. The function you write can be "contravariant" in the domain and "covariant" in the codomain. In C# if an generic type variable of an interface is only used as a return value (codomain value) then it can be designated covariant with the keyword "out". If the variable only appears as the type of a input parameter, then it can be designated contravariant with the keyword "in". But if the type variable appears as both a return type and a parameter type, then it must be invariant. In a separate program I will demonstrate when this feature will be useful. */ using System; interface I { object f(); void g(string x); } /* The following class will not compile in C#. Java will accept the covariant f but not the contravariant g: class A : I { public string f() { return "abc"; } public void g(object x) { } } But the following will compile: */ interface I2 { Q f(); void g(R x); } class A2 : I2 { public string f() { return "abc"; } public void g(object x) { } } public class var { public static void Main() { I2 x = new A2(); // works! Console.WriteLine(x.f()); x.g("xyz"); } } /* What's wrong with the following interface? interface I3 { T get(); set(T x); } Since T is also a codomain type, it cannot be contravariant, and since it is a domain type, it cannot be covariant either (out T also won't work). It can only be *invariant*. */