Covariance and Contravariance in C# 4.0

Over the last couple of days I have read a number of blogs on the topic of covariance and contravariance, a new feature to be introduced in the upcoming C# 4.0 release. Whilst most of the blog posts were happy to provide a detailed account of what these terms mean and provide some simple examples, none really hit home how they differ from polymorphism (or assignment compatibility, the ability to assign a more specific type to a variable of a less specific type). That is, until I stumble across this excellent post on Eric Lippert’s blog which explains exactly that!

Covariance

For those of you who’s new to the topic of covariance and contravariance, here’s some code snippets to demonstrate what covariance means and the problem with it:

class Animal {}
class Dog : Animal {}
class Cat : Animal {}

void ChangeToDog(Animal[] animals)
{
    animals[0] = new Dog(); // this throws runtime error because of type mismatch
}

void Main()
{
    // this is fine, by virtue of polymorphism
    // this is also known as 'type variance' because types of the two variables 'vary'
    Animal animal = new Cat();

    // this is also fine, this is called 'covariance'
    // this works because the rules for arrays is co-ordinated with the rules for variance
    // of the array element types
    Animal[] animals = new Animal[] { new Cat() };

    // here's the problem - because the ChangeToDog method accepts an array of Animal
    // objects therefore it has to accept an array of Cat objects, and the subsequent
    // assignment is also valid to the compiler because it follows the rules of
    // variance, but clearly, you can't assign a Dog to an array of Cat objects!
    ChangeToDog(new Cat[] { new Cat() });
}

Firstly, the problem demonstrated above throws a runtime error, which is not ideal as we C# developers prefer compile time errors. But the main issue here is that this is a WTF error because it catches you completely by surprise, as you’re writing this method there is no way for you to know that the consumer of your method will call it covariantly and cause a runtime exception to be thrown for an otherwise perfectly valid assignment.

So when generics became available in C# 2.0, the designers of C# took away the ability to use type variance with generics as you can see from the code snippets below:

class Animal {}
class Dog : Animal {}
class Cat : Animal {}

void ChangeToDog<T>(List<T> animals) where T : Animal
{
    // compile time error
    animals[0] = new Dog();

    // same as above, compile time error
    animals[0] = (T) new Dog();

    // this compiles but throws a runtime type mismatch error as before, but no longer
    // a WTF error because this has 'suspicious looking code' written all over it!
    animals[0] = (T) (object) new Dog();

    // this is pretty much the safest way to do the type of casting we want
    if (animals is List<Dog>)
    {
        animals[0] = (T) (object) new Dog();
    }
}

void Main()
{
    // this no longer works!
    List<Animal> animals = new List<Cat>() { new Cat() };
}

The inheritance relationship between a Cat and an Animal is not preserved because there was no covariance support for generics in C# 3.5.

In C# 4.0, you will be able to use covariance with interfaces on types that are only used at output positions which makes it safe and prevents the WTF exception from the first example from happening.

To use covariance in your code, you need to mark a type variable with the out keyword, here’s the new look IEnumerable<T> and IEnumerator<T> in C# 4.0:

public interface IEnumerable<out T> : IEnumerable
{
    IEnumerator<T> GetEnumerator();
}

public interface IEnumerator<out T> : IEnumerator
{
    bool MoveNext();
    T Current { get; }
}

Contravariance

Conversely to covariance, contravariance reverses the inheritance relationship of T:

public class CustomEventArgs : EventArgs { }
// delegate with handler which accepts type CustomEventArgs
public EventHandler<CustomEventArgs> MyDelegate;
// handler with a less specific type EventArgs
public void MyHandler(object sender, EventArgs e) { }

void Main()
{
    // this works thanks to contravariance
    MyDelegate += MyHandler;
}

Right now, contravariance is supported in generic delegates in the handler’s event argument as I have demonstrated above, but not in the type parameter T so this bit of code doesn’t compile:

class Person {}
class Student : Person {}

// throws compile error for type mismatch because Action<T> is not contravariant in T
Action<Student> studentAction = (Person p) => { /* do something */ };

In C# 4.0, you can use contravariance on a type that is only used in input positions which allows you to cast in the reverse direction (e.g. from Animal to Dog).

The in keyword can be used to mark an input type as contravariant, the limitation is that you are only allowed it for reference conversion, so no boxing allowed!

public interface IComparer<in T>
{
    int Compare(T left, T right);
}

This means you will be able to use an IComparer<object> as though it was a IComparer<string>.

As you’d imagine, covariance and contravariance is also supported in the type parameters for generic delegates, the default Func and Action delegates have all been marked with the appropriate in or out keywords for each type parameter.

Further reading

Eric Lippert’s 11-part (so far!) blog entries on Covariance and Contravariance

Joe Albahari’s presentation on What’s New in C# 4.0

Functional programming with Linq – IEnumerable.Aggregate

As I was learning functional programming with F# I came across the List.reduce function which iterates through a list and builds up an accumulator value by running another function against each element in the list.

Back to the more familiar C# territory, LINQ has introduced some functional features to C# and one of these is the Aggregate function on IEnumerable<T> which works in the same way as the List.reduce function.

In the following example, you can use the Aggregate function to built up a comma separated string from an array of string:

var strings = new List<string> { "Jack", "Jill", "Jim", "Joe", "Jane" };
// this returns "Jack, Jill, Jim, Joe, Jane"
var comSeparatedStrings = strings.Aggregate((acc, item) => acc + ", " + item);

Converting Hex string to Int in C#

For a hex literal that’s not prefixed you can quite easily convert it using int.Parse in C#:

string hex = "142CBD";
// this returns 1322173
int intValue = int.Parse(hex, System.Globalization.NumberStyles.HexNumber);

But as you’ve probably noticed, most hex literals are prefixed with 0x (e.g. “0x142CBD”) which would throw a FormatException if you try to parse it using the above code.

In order to parse a 0x prefixed hex literal you need to use the Convert.ToInt32(string value, int fromBase) method instead:

string prefixedHex = "0x142CBD";
// this works, and returns 1322173
int intValue = Convert.ToInt32(prefixedHex , 16);

Buzzword Buster – DDD

Definition:

Domain Driven Design (DDD) is an approach to software design which puts the focus on the problem domain and provides a structure for making design decisions to accelerates software development for complicated domains. The key components in DDD include:

Domain: the subject area to which your program is applied

Model: abstractions that describe aspects of a domain and can be used to solve problems related to that domain

Domain Experts: people with the most complete knowledge about the world your system will live in

Ubiquitous language: a language around the domain model used by all team members, the language is ubiquitous because it is present everywhere

Purpose:

Traditionally .Net applications are developed using a data-centric approach where you build your system around your understanding of the data – creating all the tables and the relationships in the Database and then mirror them in your .Net code. This approach is popular because of the ease and speed with which you can create a fully functional system from the ground up.

DDD on the other hand, focuses on the problem domain as a whole which covers not only the data but also the behaviour. DDD encourages greater involvement from domain experts, the idea is to build your system in a manner that’s reflective of the actual problem domain you are trying to solve and let the domain drive your design decisions.

One of the greatest challenges in developing a new system is to learn and understand the new business, which is why a single, shared language (the ubiquitous language) between the users and the developers can go a long way to reduce misinterpretations and create a more concise and effective communication amongst all interested parties.

Parting thoughts…

It is important to remember that whilst DDD is better than the data-centric approach in some cases, the reverse is also true.

Also, DDD carries with it the overhead on the developers’ part to become proficient (or sometimes experts!) in the problem domain and being able to communicate with the users in an common language.

Mastering both programming skills and business knowledge in the core problem domain is difficult and takes significantly longer than the course of developing an application – seasoned developers in the Financial sector would no doubt agree with this! This is one of the reasons why knowledge in a particular area (equities, derivatives, etc.) is such a valuable asset and developers who also qualify as domain experts in a business area are so highly sought after and compensated.

On the hand, it is also why so many find it hard to break into Finance despite boasting impressive development skills, and why many others become typecast with a specific industry/area and find opportunities outside their familiar territories hard to come by.

During my time with Credit Suisse I have come across many developers who have spent their entire professional career in the same business area, becoming domain experts in their own right. Though personally it’s not what I’m looking to get out of my career I can definitely see the merits of doing so and appreciate the enthusiasm they have for their problem domains.

Further reading:

Domain Driven Design by Eric Evans

Throwing exceptions the right way

Use ReSharper? Notice every time ReSharper sees code like this:

catch (Exception ex)
{
    // some exception handling, or logging here
    throw ex;
}

it complains, and tells you to get rid of the ex for the reason ‘Exception rethrow possibly intended’?

The reason ReSharper is warning you about an ‘exception rethrow’ is that when you rethrow an exception it replaces the stack trace of the original exception with the current location. So if you print the stack trace further up the code you will not be able to see the statement which caused the exception in the first place!

For this reason, you should ALWAYS use this instead:

catch (Exception ex)
{
    // exception handling
    throw;
}

Handling multiple exceptions

Further on exception handling, if your code might throw multiple types of exceptions and you want to handle the exceptions differently then you can build up a hierarchy of catch clauses from the most specific (SqlException e.g.) at the top, to the least specific (Exception) at the bottom like this:

try
{
    // do something that can might throw an exception
}
catch (SqlException sqlEx)
{
    // retry on timeout or deadlock for example?
}
catch (Exception ex)
{
    // handle more generic exception
}
finally
{
    // put any clean up operations here
}

It’s worth noting that, if you are catching the more general exceptions further up the chain your exception handling code for more specific types of exception lower down the list will never be called! But fortunately tools like ReSharper will warn you first :-)

Another thing you might want to consider is to wrap the built-in exception types into a custom Exception type and maybe use an enum to categorise the different exceptions into well defined types that your application understands (e.g. ServerError, FeedError, DatabaseError, etc.).

In the case of WCF services, you can also specify fault contracts for each operation and in your catch clauses on the server side wrap all exceptions into faults so when exceptions happen they don’t fault your channel. For more on WCF error handling and fault conversion, have a look at this article.