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!