Fabulous Adventures In Coding
Eric Lippert is a principal developer on the C# compiler team. Learn more about Eric.
(This is part three of a four part series; part two is here, part four is here.)
Part Three: Bad hierarchical design
The reason we humans invented hierarchies in the first place is to organize a complicated body of stuff such that there’s a well-defined place for everything. Any time you see a hierarchy where there are two levels with the same name, something is messed up in the design of that hierarchy. And any time you see a hierarchy where one of the interior nodes has a single child, again, something is probably messed up.
Krzysztof points out in the annotated Framework Design Guidelines that the fundamental point of namespaces is not actually to allow you to disambiguate two things with the same name. (Ideally there would never be a situation where two things had the same name in the first place; coming up with a mechanism to enable that problem and then deal with it seems counterproductive.) Rather, the point of namespaces is to organize types into a hierarchy that is easy to understand.
That is, the point of namespaces is not just to keep similarly-named things separated, but rather, to group things that have something in common together so that you can find them. If you don’t think that there are two or more things that could go into a namespace, then it is probably not a good namespace.
My original example was a namespace MyContainers.List containing a class List. Could any other class go into MyContainers.List? No. The right design is to either move the class List into the MyContainers namespace, or to make the namespace MyContainers.Lists, plural, and have it contain more than one thing, say, MutableList and ImmutableList.
The commonality that groups a set of types into a namespace could be anything. System.Collections.Generic groups collection types by an implementation detail: they’re all generic. System.IO groups types by related functionality. Top-level namespaces like “System” and “Microsoft” group things by whether they are part of the core functionality of the platform, or are Microsoft-specific extensions to it. But the point is that each of these namespaces groups a large number of things by some shared characteristic. A namespace containing a type of the same name indicates a failure in the design of the hierarchy.
Next time: It makes a bad situation worse.
"If you don’t think that there are two or more things that could go into a namespace, then it is probably not a good namespace."
One counterexample might be if you wanted to allow clients of your library to specifically choose whether or not to enable certain extension methods - especially if you are adding potentially annoying (yet potentially helpful) extensions to things like System.Object, or "T where T : class". The only way to do that is to put the static class in its own namespace.
Disambiguating names is less important than disambiguating _meanings_. I can disambiguate two "Table" classes with namespaces such as NS1.Table and NS2.Table, but I"m no better off. Their names aren't ambiguous but their meanings are. However, using logical namespaces such as Html.Table and Database.Table makes it quite clear what's going on. I could have ignored namespaces and used a prefix to achieve the same result. Either way, the logical differences are more significant than the syntactical differences.
I agree, the same name will involve lots of confusion!