Extra! Extra! Generics CLS-compliant in Whidbey! [Peter Drayton]

As you may have already heard, the November CTP of Visual Studio 2005 Standard Edition was posted for MSDN subscribers earlier this month. CTPs are unsupported, pre-release software - and also a great way to get an early look at what's coming down the pike in the next full beta (Beta 2 in this case).

One of the interesting changes in this release is that the C# & VB.NET compilers now treat generics as CLS-compliant. If you're brand new to CLR generics and working primarily in one of the Microsoft languages this may not seem like a big deal (C#, VB.NET & MC++ are generics producers & consumers, and J# is a generics consumer) - but if you've been following the development of CLR generics for a while, or you're working in (or developing) one of the many other languages on the platform, this is a change worth understanding.

Since CLS consumption defines the bar that all languages targeting the CLR must meet in order to consume the Framework APIs, adding a feature like generics to the CLS means that all .NET languages (currently, about 30) would need to be updated. Our original plan had been to add generics to the CLR in Whidbey, and to the CLS in Orcas. This approach enabled WinFX, Indigo, etc. to take full advantage of generics in their API design while giving 3rd-party languages a super-long runway to implement their generics support.

The downside of this plan was that it meant developers producing components with Whidbey would have to make a choice between multi-language API reach (producing CLS-compliant non-generic APIs) and API elegance (optimizing for generics & producing non-CLS-compliant APIs). Furthermore, the August Longhorn/WinFX news meant that any developer targeting WinFX would be using the Whidbey CLR, compilers & CLS rules when writing WinFX code - which treated generics as non-compliant. Ick.

To make a long story short, there was interest in generics from a wide variety of languages and we got lots of feedback that customers (and our own developers) would prefer to not have to make the tradeoff between API reach and API elegance. As a result of this interest & feedback, we decided to accelerate the introduction of generics into the Whidbey CLS and update the C# & VB.NET compilers to match. These changes were implemented post-Beta 1 and will be included in the general Beta 2 release, but MSDN subscribers can kick the tires now now via the November CTP. Give it a try, and let us know what you think!

At this point you might be wondering about the new CLS rules, and what they mean for your code. If you are a developer working in C# or VB.NET, these new rules will have very little impact on you - with minor exceptions the generics code you write is CLS-compliant, and the compilers do the mechanical transformations and checking where possible to ensure that you are producing CLS-compliant generic APIs. If you are a language implementor or are working in MSIL, Reflection/Emit or advanced CodeDom, you will probably want to to understand the new rules in a little more depth.

Traditionally, the CLS has supported the notions of consumers, extenders and frameworks. The CLS for generics builds on this approach, taking the position that:

  1. Consumers must support consuming generic types and methods.
  2. Extenders must support consuming and extending generic types and methods, but need not support defining new generic types and methods, or overriding existing generic methods.
  3. Frameworks may expose generic types and methods if they conform to the new CLS rules for generics.

The new CLS rules were worked out in close cooperation with ECMA TG3 - a smart & talented group of individuals representing a cross-section of large & small companies; commercial & academic interests; hardware & software vendors; platform & language implementors. The precise rules are captured in the latest ECMA TG3 working draft, due to be posted on the MSDN ECMA site in the near future. In the interim, here is a synopsis of the six new rules with comments in italics:

  1. The name of a generic type must encode the number of type parameters declared on the type. The name of a nested generic type must encode the number of type parameters newly introduced to the type.
    Typically done by the compiler automatically, you may encounter these "mangled" names when using Reflection over generic types.
  2. Nested types shall have at least as many generic parameters as the enclosing type. Generic parameters in a nested type correspond by position to the generic parameters in its enclosing type.
    Typically done by the compiler automatically, this essentially means that nested types "inherit" the type parameters from their enclosing type.
  3. A generic type must declare sufficient constraints to guarantee that any constraints on the base type or interfaces would be satisfied by the generic type constraints.
    The C# & VB.NET language already requires re-declaration of type constraints in this manner.
  4. Types used as constraints on generic parameters must themselves be CLS-compliant.
    The natural continuation of existing CLS rule 11.
  5. The visibility and accessibility of members (including nested types) in an instantiated generic type shall be considered to be scoped to the specific instantiation rather than the generic type declaration as a whole.
    This rule ensures languages with different accessibility rules for generic instantiation can interoperate.
  6. For each abstract or virtual generic method, there shall be a default concrete (non-abstract) implementation.
    If you provide an abstract or virtual generic method, provide a concrete implementation so languages which can't define new generic methods can consume your API.

As mentioned earlier, the precise ruletext (and all the gory details re: the new metadata tables & IL instructions for generics) will be on MSDN soon - in the meantime, feel free to post additional questions or comments on this blog entry, and let us know what you think about having generics in the Whidbey CLS!

Comments (31)

  1. I have a couple of questions related to #6 at the end of your post:

    1) Isn’t an "abstract method with a default concrete implementation" not an abstract method at all, but a virtual one? And doesn’t a virtual method always have a concrete implementation? In other words, couldn’t this requirement be restated as "abstract generic methods are prohibited?"

    2) Does "generic method" mean just methods with their own type parameters (as in void Foo<T>(T t) {}) or does it also include methods whose parameters or return types are generic parameters of their enclosing type (as in class Foo<T> { void Foo(T t) {} })?

    Another more general question: You mention that J# is a generics consumer in Whidbey. Could you give more information about exactly how J# is able to consume generics in a language that doesn’t have any such concept? Has any effort been made at all to provide any level of compatibility, or at least non-conflict, with Java 5.0’s own generics implementation, which is implemented in a radically different way than Whidbeys? For example, how would J# code work with a List<String>?

  2. I’m a little disappointed not to have gotten any response whatsoever to my questions. I don’t always expect responses from blog comments, but when you specifically ask people to leave feedback and questions in the comments, it’s a little rude to then ignore them.

    I still love Microsoft bloggers in general, but if you’re going to specifically suggest a particular form of feedback, you really ought to give some feedback back.

  3. Ken Brubaker says:

    That generics will be a required part of the CLS as of the .NET 2.0 release is huge news for the developer, who now has to deal with them in public APIs whether you like to or not.

  4. Anson Horton says:

    In Whidbey, J# shall provide the ability to consume any ".NET generic type" (whether it is part of the .NET Framework, or authored in other languages). Note that this includes the ability to consume generic classes, generic interfaces, constrained generic types, generic methods, instantiation at primitive types and value types and reference types. J# shall provide full access to all of the generic APIs in the .NET Framework. While most of the syntax will be similar, J# does not support wildcards. Code that is using such wildcards will need to be modified before compiling with J#. Also, the libraries that ship with J# will remain at their current level. Post-Whidbey, J# shall introduce support for authoring generics, and we shall certainly be keeping compat with Java 5.0 generics in mind. The documentation delivered with J# (accessible through MSDN too) illustrates the support for consuming generics. Also, refer http://www.microsoft.com/india/msdn/chat/transcripts/150.aspx for a brief decription of what is new in Visual J# 2005 by Pratap Lakshman.

  5. Lu says:

    The only question is when vs 2005 will be released. 2005 is only in days.

  6. I think it’s been announced that VS2005 will be released at the PDC in September but I’m not 100% sure.

    All the J# information I can find including the link Anson gave and every other link I followed from those pages still don’t have any actual syntax for how J# supports Generics, enums and valuetypes. It’s interesting to hear that they do, but surely the syntax is kind of important to reveal?

    I don’t really feel like installing the VJ# Express beta from months ago just to see if I can figure out what syntax is used, especially when (based on my experience with C# express) I’d still be reduced to pressing random characters and hoping Intellisense would give me some hints. It took me forever to figure out the use of the "where" keyword in C# because as far as I could tell there was no documentation on it anywhere in the Express product (and I was offline at the time).

  7. Michael Blome says:


    As a side note I’m curious why you weren’t able to find the docs on "where" in C# Express. We did document it extensively in the local docs. Was it a problem with search or the index perhaps?

  8. Well, the main problem was that I didn’t know what I was looking for, so I didn’t know to search for "where". It was a while ago, so I’m not too sure of the details any more, I just remember being very frustrated about it.

    Perhaps I was looking at the wrong docs, but if I’d been in "real" VS I would have gone straight to the C# language reference (I have that bookmarked) and found the part that described the syntax of a type declaration. In Express, it all seemed to be very basic overviews of stuff without many examples or detail; if there was some detailed reference documentation in there, I never found it.

    I can’t remember if I tried the search – I may have been trying to find it through the table of contents. The index wouldn’t have been helpful because I had no idea what keyword I was looking for (I was expecting something like Java’s Foo<T extends Bar> syntax and getting annoyed that I kept getting red squigglies under my ":", but you can’t exactly search the index for ":" – one of the few syntactic decisions which Java did better than C# at – and even if you could it wouldn’t have been the right thing to search for anyway – and this sentence really is absurdly long).

  9. So if generics are now CLS compliant, does that mean we can eliminate the System.Collections.ICollection interface (and all its brethren) in favor of System.Collections.Generic.ICollection<T> (and all its brethren), rename System.Collections.Generic to System.Collections, and generally move to only having one collection namespace? It seems to me that CLS compliance was the major reason not to do this. Incurring this breaking change now will mean much less hassle in the future for MS and everyone else, since frameworks won’t have to implement both ICollection and ICollection<T> to be useful to all consumers, and generally useful APIs won’t have to have overloads that take both ICollection and ICollection<T>. Incur the cost of switching now (which is basically typing "<object>" after all appearances of ICollection, IList, IEnumerable, ArrayList, etc. and can essentially be done by global search and replace in 95+% of cases) and we will avoid that whole set of issues.

  10. Requiring all .NET languages to have support for generics looks scary in context of


    Actually there is no way to generate any complex generic

    code using standard method of producing .NET binaries – System.Reflection.Emit. The only way is to use some external libraries / writing them by ourself for generating IL.

Skip to main content