February 2007
M T W T F S S
« Jan   Mar »
 1234
567891011
12131415161718
19202122232425
262728  

Chris Donnan : Programming - Brooklyn Style

software, trading, family, fun

Generics lack covariance/ contravariance

I spent several months doing .net 2.0 work, then, several months back to a 1.1 project. We have just moved our 1.1 project from nant to msbuild. I am a fan of msbuild, custom tasks and such - it seems like a total better solution than our nant solution. When you have complex work to do - it can get ugly fast - but it seems less ugly with msbuild. In any case - now that that project has been upgraded - I am back the past few weeks to .net 2.0. I really missed anon-delegates more than anything else. Closures are powerful, iterators rock, generics - yes - nice. All of that said - there is at least one glaring problem with generics as implemented in the current CLR.

Generics currently lack covariance/ contravariance

While delegates currently support co/contra variance - generics still lack this behavior. As someone who spends a lot of time building and co-evolving frameworks - this has proven to be troublesome for projects. This is something that irked me ~7-10 months ago and it is back to irritate me again.

Allow me to illustrate…

ArrayList< Car > = new ArrayList< Car >(); 

This is the easiest - no magic at all - same type on each side of the “=” and same type parameter. Of course - this works fine.

Next

IList< Car > = new ArrayList< Car >(); 

Of course this works - this is normal stuff; the inheritance/ implementation of the ‘left side’ of the generic instance declarations work fine (meaning IList/ ArrayList work fine). IList - sure ArrayList implements that - we are good. They also both have a type parameter of type Car - this is fine, we are good to go.

How about this:

IList< Car > = new ArrayList< Ferrari >(); 

In this example lets say Ferrari extends Car. Alas - this does not work. The inheritance/ implementation of the ‘left side’ of the equation (IList/ ArrayList) works fine - but the inheritance on the ‘right side’ of the equation (Car/ Ferrari) DOES NOT WORK. The inheritance scheme does not matter - they are not THE SAME TYPE. This is the ‘crux of the biscuit’ as they say. This is the problem I am talking about :).

Alas -

ArrayList< Car > = new ArrayList< Ferrari >(); 

This does not fix the issue - same problem - even though there is now no inheritance on the ‘left side’ of the equation - and there is simple inheritance on the rights side - it does not matter. The inheritance on the ‘right side’ of the equation does not work in CLR 2.0. Generic types are invariant unfortunately.

This article has an interesting idea on a potential syntax to denote allowed co/contravariant. The idea is that you can use a + or a - in the generic type declaration to denote desired co/contravariant behavior.

Anyhow - there is my complaint rant on generics. I would rather have them as is today than not at all - that is for sure :)

-Chris

PS - I did not point it out earlier - but all co/contravariance mean is: in one case - your supplied class is a sub-class of the type parameter, in the other case - a super-class of the type parameter.

PPS - Another issue - the new constraint does not allow new(args) to enforce that the template type allows a specific constructor - also annoying!

Share and Enjoy: These icons link to social bookmarking sites where readers can share and discover new web pages.
  • del.icio.us
  • digg
  • blinkbits
  • BlinkList
  • blogmarks
  • YahooMyWeb
  • connotea
  • De.lirio.us
  • Fark
  • Furl
  • Reddit
  • description
  • Shadows
  • Smarking
  • Spurl
  • TailRank
  • Wists

Comment on this post below

You must be logged in to post a comment.


You can leave a response, or trackback from your own site.