Wednesday, March 31, 2004

Big Bummer

Ian Griffiths asks a great question in the comments on my post about System.Xml 2.0. Here it is:


That's excellent! But I have one question: why can't I do this?:

Book book = reader.ReadAsObject < Book > ();

What's with all this casting, in a world with generics? (Of course what you really want is for the template parameter to be inferred, but sadly you cannot infer template arguments from function return types.)


A quick experiment verified my assumption: generics are not CLS Compliant, as evidenced by this code:


using System;
[assembly:CLSCompliant(true)]


namespace GenericsCLSCompliant
{
  public class App
 
{
    static void Main(string[] args)
    {
      new Class1<App>().DoSomething(new App());
    }
  }


  public class Class1<T> where T : new()
  {
    public void DoSomething(T t)
    {
    }
  }
}


and the ensuing compiler error:


error CS3024: 'GenericsCLSCompliant.Class1<T>': type parameters are not CLS-compliant


What this means is that the important bits of the CLR libraries cannot leverage generics. This is a crying shame.

4 comments:

  1. I thought that they simply hadn't finalized what would be CLS compliant and what wouldn't for generics. One of the implications of this:

    http://blogs.msdn.com/kcwalina/archive/2004/03/15/89860.aspx

    is that generics will certainly be in the CLS in the long run, although Anders comments about 'in the Longhorn timeframe', which isn't too encouraging... This one:

    http://blogs.msdn.com/branbray/archive/2003/11/19/51023.aspx

    also says that they will be compliant at some point in the future, but again it's pretty vague.

    So perhaps they won't be compliant in the Whidbey^H^H^H^H^H^H^H VS.NET 2005 timeframe. *sigh*

    And thanks for putting the phrase "Big Bummer" in close juxtaposition with my name so that it reads "Big Bummer Ian Griffiths asks..." ;-)

    ReplyDelete
  2. The XML team can provide *2* methods, one with generics and one without and still be CLSCompliant.

    ReplyDelete
  3. Big Bummer Ian: :)

    Big Bummer Chris: Good point! I will blog a follow-up.

    ReplyDelete
  4. OK, Chris, thinking this over some more, I'm not sure it's quite so simple. While cases like this one, templatizing the return type is fairly straightforward to deal with, there are still some factors that cry out for generic support to be added to the CLS:

    1) Teams are discouraged from exposing the APIs this way, since it means doing extra work. (Chris, I know laziness is a topic especially close to your heart.)
    2) I can't use generic types as parameters to anything nearly as easily as simply templatizing return type. Think about what it would mean to provide the same guarantees that "public T Foo(Blah< X > bx, Bar< Y > by) where X : IDisposable, new() {} " achieve in one line of code. There are a non-trivial number of assertions that need to be made, and now they're *run time* violations, not compiler violations. So I maybe have to define a bunch of exceptions, and my testing gets more complicated...

    Using object as a type is, of course, the ultimate workaround, but it's going to be *at least* twice the work compared to providing a generic-only interface. Or an object-only interface. They're simply different animals.

    That said, I certainly understand that adding generics to the CLS is a huge deal, given the impact on basically every language.

    ReplyDelete