Do not name a class the same as its namespace, Part Three
(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.
(This is part three of a four part series; part two is here, part four is here.)
Comments
Anonymous
March 15, 2010
I think you could make a pretty darn convincing argument that namespaces are in fact intended to disambiguate different things with the same name. Why are they called "namespaces" and not "categories" or "taxonomies"? It actually makes sense if you think about it. In many languages (C, Objective-C, PHP) the big problem with libraries is that there's no way to make sure that the names used in one library won't also be used in somebody else's library. For example, the HTML library has good reason to have a Table abstraction and the DB library has good reason to have a completely unrelated Table abstraction. Unfortunately, the only way to be able to use them together would be to have each library use a prefix, so you'd have HtmlTable and DbTable. But then you have to hope that everybody uses a prefix and that the prefixes don't collide, which could be a problem when Dan Brown decides to use Db as the prefix for his HTML library. And since the prefix has to be typed in every time one of the names is used it has to be short, which encourages collisions. Hierarchical namespaces are the perfect solution to this problem. As for organizing types into an easy-to-understand hierarchy, why would the compiler care? The compiler doesn't need to understand the hierarchy; programmers do. At that point it's a documentation issue which could be addressed with attributes or documentation comments, and the compiler wouldn't have to care if you use the same name for both the genus and species. Of course you could make the analogy to a filesystem: A filesystem has hierarchical directories to group files together, not to allow two files to have the same name. However, that's different because I frequently browse the filesystem hierarchy directly, while I only browse the BCL namespace hierarchy directly when I use Reflector. Otherwise I just browse the documentation which need not have any relation to how the compiler sees the classes the same way the Win32 API documentation is hierarchical even though it is all in a flat namespace. Furthermore, it seems like if the only purpose was to organize types, a type should be allowed to be in multiple places. Why should I have to decide whether ImmutableList<T> goes into MyContainers.Lists, MyContainers.Generic, or MyContainers.Immutable? I should be able to categorize it as Generic, List, and Immutable all at the same time.Anonymous
March 15, 2010
I dont think Eric ever said that namespaces arent there to disambiguate different things. Of course namespaces are there to use in such way and should in fact be used that way. The point is that it should not ONLY be used thinking in that particular functionality. If you do, then having a class with the same name as the containing namespace is obviously not a problem, same as having a file named as the containing folder isnt a problem at all (to follow your analogy). But when you look at the bigger picture of namespaces and that apart from helping avoid name-collisions they should be used to represent logical and well thought heirarchies, then having a namespace containing a class with the same name doesn't seem such a good idea.Anonymous
March 15, 2010
The comment has been removedAnonymous
March 15, 2010
Well, for me AnimalCollection seems far better than Animals because it makes it obvious that it's collection of animals. Moreover it's not a good idea to have two classes within the same namespace that differ only in single letter. If you stick to .NET naming guidelines (namespaces in plural, collections with Collection suffix) then you won't run into this kind of problems. I can agree that as you said "sometimes logical names happen to coincide", but in my opinion it's a sign that your hierarchy wasn't as well thought out in the first place, so it's probably time for some refactoring. BTW, your second example is so contrived that it should be taken out and shot. ;)Anonymous
March 15, 2010
The comment has been removedAnonymous
March 15, 2010
@Gabe sorry but the animals example doesnt work for me. The class should be names AnimalCollection which is the way the Framework is designed too: System.Windows.Forms.FormCollection, not System.Windows.Forms.Forms I see no name-collision at all. Having to name a class slightly differently without losing one single bit of the name's meaning is not such a big deal IMHO.Anonymous
March 15, 2010
I guess my point wasn't quite clear enough. I meant that having a class named Animals in a namespace named Animals doesn't indicate a failure in the design of the hierarchy -- it merely indicates a failure to follow the .Net naming conventions.Anonymous
March 15, 2010
Well, it depends on how you look at it. I consider it a flawed hierarchy because it has a flawed naming convention, even if its conceptually sound. Naming is many times just as important. You could create a great hierarchy from a conceptual standpoint but still manage to make it almost completely useless through horrible naming conventions. So IMHO having a class named Animals in a namespace named Animals IS a flawed hierarchy...not conceptually but still flawed by a serious usability issue. When you think up the hierarchy its easy to spot the Animals issue beforehand and name the class AnimalCollection. If you validate hierarchy design only from a conceptual standpoint then I understand your point of view. I try to not separate conceptaul correctness from sound naming when I design as both can normally go hand in hand without it being a problem.Anonymous
March 15, 2010
Well, I'm (mostly) with Gabe on this one. Namespaces are primarily about partitioning the namespace. Any sort of taxonomy is a secondary concern. That's not to say it is unimportant, but it is not the primary purpose of the language feature. Perhaps C#'s namespaces were more inspired by Java packages, which are more about the classification. However overdoing the hierarchical thing can lead to more fragile code as too many assumptions are often pushed into a non-functional aspect of the code. I had a similiar discussion on Stackoverflow here: http://stackoverflow.com/questions/2108172/c-namespaces-comparison-to-java-packages/2108209#2108209Anonymous
March 16, 2010
Design is what is more of us (starters) do not care a lot about and are more interested in getting things done. Do appriciate your effort as you higlight some very basic things which are of really great importance.Anonymous
March 16, 2010
The comment has been removedAnonymous
March 16, 2010
Gabe: "And since the prefix has to be typed in every time one of the names is used it has to be short, which encourages collisions." You can create short namespace aliases for solving this problem. eg.: using OM = XY.ObjectModel; OM.User user = OM.User.Create(...); Using short aliases for namespaces are rather common. When you create n-tier application, where the entitites has type representation in every tier in worst case, that can be tricky scenario. Or when you create DTO-s for your entities, you also face with this problem.Anonymous
March 16, 2010
The comment has been removedAnonymous
March 16, 2010
Fix: "I like the namespaces which ends with "Model", such as XY.ObjectModel, XY.ServiceModel, XY.TableModel, XY.SecurityModel and so on. I found it rather practical, becasue it express some kind of aspects, which are independent by its nature, and they are 'wide' enough to serve as a base for 'taxonomization'." Separating types by aspects can be good idea. ps. Sorry for flooding.Anonymous
March 17, 2010
The comment has been removedAnonymous
March 17, 2010
"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.Anonymous
March 18, 2010
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.Anonymous
March 25, 2010
I agree, the same name will involve lots of confusion!