Today, I’m going to talk about the way my attitude towards using namespaces has pretty much done a complete reversal over the last couple of years. I started off thinking that they looked great, progressed to mild concern that they seemed to be causing unexpected difficulties, and eventually realized that they can become unmanageable if allowed to grow out of control. Just like a bunch of tribbles. (Yes, the title is a Star Trek reference :).
To jump to the punch-line, I’ve come to the conclusion that highly fragmented hierarchies of namespaces (such as are found in .Net and encouraged by the Visual Studio C# IDE) make life harder rather than easier. Instead, I would recommend either name mangling strategies (incorporating an identifying string in the object name) or always using fully qualified names in your code (instead of “using” statements).
Phase I: Infatuation
When namespaces were first introduced into C++, I thought they looked like a great idea. It seemed wonderful to not have to worry about managing name collisions. Unfortunately, for over a decade I didn’t have an opportunity to use them; my Physics codes were standalone executables (and so name conflicts weren’t an issue), and ACIS was written before they were portable to all compilers. Actually, ACIS was written before they were introduced into C++. In the tribble analogy, everyone else got to play with these cool critters but I didn’t have one.
Phase II: Nagging Doubts
This changed when I started working with C#, especially in my personal projects at home. The .Net library makes extensive use of namespaces to indicate areas of functionality, plus the Visual Studio IDE assumes you want this sort of hierarchy in your code. If you create a folder within your solution to manage an area of functionality, for example a Market component in an economics simulator with root namespace Econ, then the Visual Studio class wizard “helpfully” puts any classes you add to that folder into the “Econ.Market” (sub-)namespace. And that is where the trouble started. (If anyone knows how to turn this behavior off, please post a reply – I’ve been unable to find a way to do it.)
I quickly found myself getting frustrated by not having the correct set of “using” statements in my code, and having difficulty figuring out which “using” statements I needed to include. For example, if I had a Trader class in a Actors folder (and corresponding namespace) and a Pit class in the Market folder, then I would regularly get compile errors when I tried to use the Trader class without “using” statement for the Econ.Actor namespace. And the really frustrating part was that it wasn’t immediately obvious which namespace was missing – I would have to find the class then look to see which namespace it was in. I now realize that the problem that I was running into is that namespaces (or more precisely “using” statements) lead you to write non-self-documenting code. In other words, if I write the code
Market market = new Market();
GoodsType goodsType = new GoodsType();
Pit pit = market.GetPit(goodsType);
I don’t have any visual indication in that region of code as to which namespace Pit, Market, or GoodsType live in. And if they come from several namespaces, I don’t know which “using” statement corresponds to which class.
This is very similar to the C++ “which header file declares this class” problem, for which a really good solution is to simply make the header name identical to the class name. CGM uses this naming convention and I highly recommend it – you don’t have to think when writing your include statements.
Phase III: Regret
The final driver on my voyage of discovery was C3D development (in C++). When we first started writing strong commands, I had the bright idea to use a namespace hierarchy to put a structure on the vast sea of commands we would be writing. Unfortunately, it didn’t work out as planned. Even though we only introduced a few namespaces, they still made life much more difficult than a simple name mangling scheme would have. Part of the problem is that the compiler errors when you get the namespace wrong are not helpful: we had to train ourselves to ask “did we get the namespace right” when we see an “undefined symbol” error for a class that we’re sure has the header included. An especially nasty error occurs when you try to include a header file inside a namespace block (this typically happens if you’re using templates and so want to do another round of includes for the method definitions). If I had it to do over again, I’d settle for a simple “_SPA” or “_CGM” at the end of each class name, e.g. Property_SPA rather than Spatial::Commands::Property. In tribble language, I feel like Kirk standing awash in a sea of tribbles.
Phase IV: Lessons Learned
The first thing to make clear is that I am NOT saying that namespaces are bad. The fundamental problem that namespaces solve is the ability for application writers to manage naming clashes between libraries from different vendors. I think it’s a great idea for every company selling component software to put everything into a single company namespace.
The problems I see come from trying to group classes into complex hierarchies, especially if you then use “using” statements to erase knowledge of the hierarchies. I’ve come to the conclusion that any such grouping should be as simple as possible, and that the primary goal of the grouping should be avoiding name clashes rather than imposing a component structure on the classes. The reason for this is that classes move between components fairly easily, especially if the component structure is very fine-grain. If every time a class moves you have to do a major renaming effort (either to fix using statements or to rename the class) then you’ll generate a lot of worthless work for yourself.
With this in mind, I currently think a name mangling scheme, with the disambiguating string at the end is best, i.e. something like ClassName_NS. The reason for putting it at the end rather than at the beginning is to help search – if you’re looking for class “Beagle” but are not sure which namespace you’re in, then you just need to look for “Bea*” in a list of all class names.
All of the above being said, I shudder to think about trying to solve this problem in a huge organization. Would .Net really be easier to use if they had used the above naming scheme rather than relying on namespaces?
These Stories on 3D Modeling
ACIS, 3DScript and SAT are registered trademarks of Spatial Corp.
No Comments Yet
Let us know what you think