The development of a Java VM for .NET
I came across an interesting Whidbey beta 1 CLR feature today. As far as I can tell this hasn't been documented anywhere yet, but the Whidbey beta 1 CLR supports covariant and contravariant generic type parameters.
This is a really interesting feature. If C# would support it (at the moment it doesn't), you'd be able to do something like this:
interface IReader<T> { T Get(); }
interface IWriter<T> { void Put(T t); }
class Test<T> : IReader<T>, IWriter<T> { T t; public T Get() { return t; } public void Put(T t) { this.t = t; } } class Driver { static void Main() { Test<string> t1 = new Test<string>(); t1.Put("covariance"); IReader<object> rdr = t1; Console.WriteLine(rdr.Get()); Test<object> t2 = new Test<object>(); IWriter<string> wrtr = t1; wrtr.Put("contravariance"); Console.WriteLine(t2.Get()); } }
Notice that in the first highlighted line we're assigning an object reference that implements IReader<string> to a local variable of type IReader<object>. This is covariance and it is type safe because the IReader<T> interface only returns T. In the second highlighted line we assign a reference that implements IWriter<object> to a local of type IWriter<string>, this is contravariance and this is also type safe, because IWriter<T> only accept arguments of type T.
Unfortunately, C# doesn't yet seem to support this feature, but if we manually write the IL, it'll run on the Whidbey beta 1 CLR (and it is fully verifiable):
.assembly extern mscorlib {} .assembly test {} .class interface public abstract 'IReader`1'<+([mscorlib]System.Object) T> { .method public abstract instance !T Get() cil managed {} } .class interface public abstract 'IWriter`1'<-([mscorlib]System.Object) T> { .method public abstract instance void Put(!T t) cil managed {} } .class public 'Test`1'<([mscorlib]System.Object) T> extends [mscorlib]System.Object implements class 'IReader`1'<!T>, class 'IWriter`1'<!T> { .field private !T v .method public virtual instance !T Get() cil managed { ldarg.0 ldfld !0 class 'Test`1'<!T>::v ret } .method public virtual instance void Put(!T t) cil managed { ldarg.0 ldarg.1 stfld !0 class 'Test`1'<!T>::v ret } .method public specialname rtspecialname instance void .ctor() cil managed { ldarg.0 call instance void [mscorlib]System.Object::.ctor() ret } } .method static void Main(string[] args) cil managed { .entrypoint .locals init ([0] class 'Test`1'<string> t1, [1] class 'IReader`1'<object> rdr, [2] class 'Test`1'<object> t2, [3] class 'IWriter`1'<string> wrtr) newobj instance void class 'Test`1'<string>::.ctor() stloc.0 ldloc.0 ldstr "covariance" callvirt instance void class 'Test`1'<string>::Put(!0) ldloc.0 stloc.1 ldloc.1 callvirt instance !0 class 'IReader`1'<object>::Get() call void [mscorlib]System.Console::WriteLine(object) newobj instance void class 'Test`1'<object>::.ctor() stloc.2 ldloc.2 stloc.3 ldloc.3 ldstr "contravariance" callvirt instance void class 'IWriter`1'<string>::Put(!0) ldloc.2 callvirt instance !0 class 'IReader`1'<object>::Get() call void [mscorlib]System.Console::WriteLine(object) ret }
Notice the plus and minus signs in the interface declarations to signal that a generic type parameter is covariant or contravariant.
Remember Me
I apologize for the lameness of this, but the comment spam was driving me nuts. In order to be able to post a comment, you need to answer a simple question. Hopefully this question is easy enough not to annoy serious commenters, but hard enough to keep the spammers away.
Anti-Spam Question: What method on java.lang.System returns an object's original hashcode (i.e. the one that would be returned by java.lang.Object.hashCode() if it wasn't overridden)? (case is significant)