using System; // Example of how contravariance can be useful. // The .Net IComparable interface is parameterized by a contravariant // typec variable: interface IComparable { int CompareTo(T x); } public class student : IComparable { public readonly string name; // can be sorted public student(string n) {name=n;} public int CompareTo(student other) { return name.CompareTo(other.name); } // compare strings alphabetically } // An undergrad is a student, and we may wish to inherit the CompareTo // method without modification. But the superclass CompareTo accepts // a student as an argument, not undergrad. In order to use undergrad // objects in polymorphic datastructures, such as sorted lists and trees, // undergrad would be required to implement IComparable. Thus // the question becomes, if we've inherited a method that implements // IComparable, does our class also implement IComparable? public class undergrad : student { public string major; public undergrad(string n, string m) : base(n) {major=m;} // no need to re-implement CompareTo - can inherit it. // because IComparable can instantiate IComparable // because IComparble says T is contravariant: it can be // istantiated by something more general than T. } // class student (and undergrad), implement IComparable, // BUT IT ALSO IMPLEMENTS IComparable because T can be // contravariant. That is the requirement undergrad can be replaced by // the a function that accepts a more general type (student). // generic sorting class (as a simple example). In order to sort an array of // undergrads using this class, undergrad must implement IComparble public class sorter where T : IComparable { public void bubblesort(T[] A) { for(int i=0;i0) { T x = A[j]; A[j]=A[j+1]; A[j+1]=x; } } }//sorter public class contraex { public static void Main() { undergrad[] A = {new undergrad("alex","cs"), new undergrad("andrew","cs")}; sorter S = new sorter(); S.bubblesort(A); foreach (undergrad x in A) Console.WriteLine(x.name); // for code below (example of covariance usage): readonlydatastructure R = new mystructure(); R = new yourstructure(); // R can be mystructure OR yourstructure }//main } // This program will not compile without "in" in the updated ICompareble // interface (since C# 4.0). /* Covariance is easier to motivate because, for example, less type casting will be needed and more accurate static type checking will be possible. More polymorphic code will also be possible because the same static type can now be instantiated by a wider range of runtime types. */ interface readonlydatastructure { T get(); } class mystructure : readonlydatastructure { public string get() { return "abc"; } } class yourstructure : readonlydatastructure { public undergrad get() { return new undergrad("tom","cs"); } }