System.TimeZone2 Naming ... and related design guidelines

There is an interesting discussion on the BCL blog about a new BCL type called TimeZone2. Just take a look at the comments below the System.TimeZone2 Starter Guide post. The new type supersedes an existing type called TimeZone (which is obsolete now).

Lots of people are not thrilled with the “2” suffix. I am responsible for the guidelines (excerpt below), and so I thought I would try to provide some context:

· Some comments suggest that the BCL team just take a breaking change, i.e. remove the old type and add a new one with the same name. This is not an option for such a widely used framework. We basically have a policy against doing any intentional breaking changes. In other words, this is not negotiable :-)

· Some comments suggested using a new namespace, e.g. System.Globablization.TimeZone. This would cause all sorts of problems. The main one is that most source files import System namespace and this approach would mean that most source files have to fully qualify the new TimeZone (otherwise you would get type name ambiguity). I don’t like fully qualifying core types when I program and usability studies we conducted have shown that I am not alone. There are other issues related to the difficulty in searching for documentation on such duplicated types, referring to such types in books and in speech, etc.

· Using numeric suffixes is the last resort thing. If you have a “good name” that does not include a numeric suffix, you should use it. The problem is that sometimes all reasonable names are already taken, and that’s when the guideline is applicable. It’s what we call the best out of many bad alternatives.

Having said that, I would love the BCL team to find a new “good name” for the type. If you have a great name, post it to my or the BCL blog.

And for reference, here is the excerpt from the design guidelines:

Naming New Versions of Existing APIs.

Sometimes a new feature cannot be added to an existing type even though the type’s name implies that it is the best place for the new feature. In such case a new type needs to be added, often leaving the framework designer with a difficult task of finding a good new name for the new type. Similarly, often an existing member cannot be extended or overloaded to provide additional functionality and a member with a new name needs to be added. The following guidelines describe how to choose names for new types and members that supersede or replace existing types or members.

þ Do use a name similar to the old API when creating new versions of an existing API.

This helps to highlight the relationship between the APIs.

class AppDomain {

    [Obsolete("AppDomain.SetCachePath has been deprecated. Please use AppDomainSetup.CachePath instead.")]

    public void SetCachePath(String path) { /* … */ }

}

 

class AppDomainSetup {

    public string CachePath { get { /* … */ }; set { /* … */ }; }

}

þ Do prefer adding a suffix rather than a prefix, in order to indicate a new version of an existing API.

This will assist discovery when browsing documentation, or using Intellisense. The old version of the API will be organized close to the new APIs as most browsers and the Intellisense show identifiers in alphabetical order.

þ Consider using a brand new, but meaningful identifier, instead of adding a suffix or a prefix.

þ Do use a numeric suffix to indicate a new version of an existing API, if the existing name of the API is the only name that makes sense (i.e. it is an industry standard), and adding any meaningful suffix (or changing the name) is not an appropriate option.

// old API

[Obsolete(“This type is obsolete. Please use the new version of the same class, X509Certificate2.”)]

public class X509Certificate { /* … */ }

// new API

public class X509Certificate2 { /* … */ }