Geeks With Blogs
New Things I Learned

On Monday I presented at the St. Louis .NET User Group, and the topic was ‘What’s new in VS2010 and .NET 4.0 Framework’.  Within the whirlwind look at all the new and cool stuff coming in the near future, the subject of Covariance and Contravariance support was discussed.  Given the time constraint I only spent 3-4 minutes at it.  I alluded to the group that the concept of Covariance/Contravariance is rather hard to understand, because it is not as intuitive as it could be; I just asked them to trust me that the support is there.

After the session, talking with some people, apparently the concept is REALLY hard to understand; and in hindsight I should’ve known this too.  It took me a good 3-4 hours of fiddling around and research to get the concept embedded in my head so it will take others the same amount of time to understand it too.

Given that the concept is rather hard, I thought I should blog about it so I don’t forget it in the future .  In this post, I’ll talk about Covariance only and I’ll post about Contravariance in the future.

Let’s start at the very, very basic level: the word itself.  Variance.  From this article on Wikipedia, I managed to synthesize that the word variance means ‘conversion of types’.  Covariance is the conversion of a type from more specific to more general.  Contravariance denotes the reverse: conversion of a type from more general to more specific.

Let’s do a simple case:

private void Test()
{
   string str = "Test";
   ProcessObject(str);
}

private void ProcessObject(object obj)
{
   // Some code...
}

In the code above we have a simple case where the consuming code declares a string, and then passes the string into a method that accepts an object.  That is Covariance in action: conversion of a type from a more specific one to a more general one (string to object).  Of course, the term doesn’t pop into mind; as developers we just see that the operation is valid since we’re passing a variable to a method that can accept the base type.  So, to go 1 step further, the following is also valid:

public class Base
{
}

public class Derived : Base
{
}

private void Test2()
{
   Derived d = new Derived();
   ProcessBase(d);
}

private void ProcessBase(Base b)
{
   // Some code...
}

As you can see, this is simple OOP in action; we’re passing an instance of the Derived class (a more specific type) to a method that can accept the Base class (a more general type).  Everything is logical, and makes sense.  Covariance in action.

So let’s push further 1 more step; we’re going to do covariance (conversion of type from more specific to more general), but without methods this time.

private void Test3()
{
   string[] strs = new string[5];
   object[] objs = strs;

   objs[0] = "Test";
   objs[1] = 7;  // This will crash the application
}

In the above code, this conversion of arrays is fully legal; however the last line will cause the program to crash.  The array conversion from string[] to object[] is not very common, but it does work.  However, since you can also use the array to assign values, this conversion is considered to be an unsafe covariance, since it will only work for valid assignment, but it cannot be checked at compile-time.

So, let’s take it 1 step further again:

private void Test4()
{
   List<string> strs = new List<string>();
   List<object> objs = strs;  // Why not?

   // To prevent the following code:
   objs.Add(5);
}

The above code won’t compile, the second line ( List<object> objs = strs; ) will fail with the error that it cannot implicitly convert List<string> to List<object> – it’s how it has been in .NET.  The initial question is why is this not allowed?  It’s because if we’re allowing the conversion, then the line afterwards (which is very illegal and we don’t want to have that kind of code ever) will crash the application definitely, and it’s not something that can be checked during compile-time.  Very similar to the prior example, but developers will use generics more so than arrays, thus this is not allowed.

In both cases, the application will break because both constructs (array and List<T>) allows assigning of values into the container.  But what if we don’t allow assigning values?  Let’s see if we can create such a scenario:

public interface IOutOnlyList<T>
{
   T this[int index] { get; }
}

public class NewList<T> : List<T>, IOutOnlyList<T>
{
}

private void Test5()
{
   IOutOnlyList<string> strs = new NewList<string>();
   IOutOnlyList<object> objs = strs;  // This should now be valid!

   // Can't assign to objs, can only get value out
   object temp = objs[0];
}

So we’re trying to create a construct just for our own use here: we have an interface (IOutOnlyList<T>) that provides a get-only indexer.  We need to have this interface implemented, so we created the NewList<T> class which inherits from List<T> and also implements IOutOnlyList<T>.  In the above code (which still won’t compile due to the assignment of strs to IOutOnlyList<object>), we’re showing that with the IOutOnlyList<T> interface, the code cannot make changes to the container; as such it should be legal.  There’s no way to write code to break the application now that’s not detectable at compile time.

That’s exactly the argument as to why this type of covariance should be allowed.  In .NET 4.0, this is now possible:

  • If the construct only allows getting the values out only
  • And the construct does not allow changing the values contained within

The code above will be legal in .NET 4.0, with the following minor change:

public interface IOutOnlyList<out T>
{
   T this[int index] { get; }
}

The change is in the signature of the generic type T, we provide an out keyword.  That out keyword tells the compiler that the interface (or class) will only use the generic type T as output, but never as input.  This allows the compiler to verify that the interface is indeed conforming to that specification (T is never used as input) and it will then allow covariance for IOutOnlyList<T> from a more specific type (string) to a more generic type (object).

The example so far is for our own interfaces; to allow covariance .NET 4.0 changes the following constructs (by using the out keyword):

Because of these changes, the code below will now work; you can assign variables of type IEnumerable<string> to type IEnumerable<object>. Since the conversion works, you can also use this to pass in parameters into methods as well.

private void Test6()
{
   IEnumerable<string> strs = new List<string>();
   IEnumerable<object> objs = strs;  // IEnumerable can't change values contained

   ProcessObjects(strs);
}

private void ProcessObjects(IEnumerable<object> objs)
{
   // Do something with objs
}

That’s the idea of Covariance in .NET 4.0 and how it is used.  Contravariance is the reverse of Covariance, but the explanation takes a bit longer…

Posted on Wednesday, September 30, 2009 7:45 AM | Back to top


Comments on this post: Covariance in .NET 4.0

# re: Covariance in .NET 4.0
Requesting Gravatar...
Thanks a lot, well explained!
Left by Xaver Birrer on Sep 06, 2010 4:18 AM

# re: Covariance in .NET 4.0
Requesting Gravatar...
Amazing explanation! Thanks!
Left by Antony Blazer on Mar 15, 2011 8:08 PM

# re: Covariance in .NET 4.0
Requesting Gravatar...
Good Example Man
Left by Mohit Jethva on Sep 22, 2011 12:10 AM

# re: Covariance in .NET 4.0
Requesting Gravatar...
This really helped me a lot to get a grasp on covariance. Eagerly awaiting the contravariance explanation.. :)
Left by Chad on Nov 30, 2011 6:01 AM

Your comment:
 (will show your gravatar)


Copyright © Muljadi Budiman | Powered by: GeeksWithBlogs.net