Courtesy of C/C++ Users Journal (July, 2003)
In [1], Bjarne Stroustrup describes the technique of namespace aliasing, which he describes as a tool for mapping verbose namespaces [2] to usable, succinct local names, as in
// In unfeasibly_long.h
namespace this_is_an_unfeasibly_long_namespace
{
void some_function(...)
{
}
}
// in client code
namespace uflns =
this_is_an_unfeasibly_long_namespace;
int main(int argc, char **argv)
{
uflns::some_function(...);
return 0;
}
This seemed a neat but unremarkable thing, and beyond using it once or twice, I'd never given it that much thought. However, I recently had occasion to use it in a context in which it proved to be very important, and it saved me from a host of unpleasant choices. Let me explain.I was working on the STLSoft [3] libraries, which were initially created as independent projects. This independence was complete, in terms of both files and namespaces, and came about due to the separate evolution of the first two projects: WinSTL and COMSTL [4]. And I did like the separation for a while due to a loathing for (both logical and physical) coupling [5]. However, as soon as there were actual classes being shared between components in different projects, the advantages of separation started to evaporate, and a better solution needed to be found.
Listing 1 illustrates this situation. The client code uses UNIXSTL's readdir_sequence, and so qualifies its reference with unixstl::. The definition of readdir_sequence in the unixstl namespace makes use of STLSoft's basic_frame_string and must qualify it with stlsoft::. All pretty standard stuff.
The problem I had stemmed from the fact that I reached a point where I wanted to move the subprojects' namespaces (e.g., comstl, unixstl, and winstl) to be within the stlsoft namespace in order that I could:
1. Cut down on the amount of qualification of stlsoft constructs in the other namespaces.
2. Introduce a code structure (in the form of namespaces) that represents the conceptual hierarchy that exists between STLSoft and its subprojects.
3. Use the mechanics of namespace hiding to allow for implicit overloading of construct via namespace.
For example, UNIXSTL could define its own basic_frame_string in the future, which would be better suited to UNIX, and would be "inherited" by definitions within the unixstl namespace for which it was visible (i.e., included into their compilation units).
Furthermore, I wanted to do this while wreaking minimum (preferably no) havoc to users of the libraries--after all, with open-source software one is always aware that users are much less tolerant of inconvenience, and much more likely to move elsewhere, than with software in which they've had to make an investment of their cold hard cash. I was left with a set of unattractive options:
1. Use #defines to define the tokens for the old namespaces to the new ones.
2. Perform some really dodgy preprocessor acrobatics, to define constructs as existing in both namespaces at once.
3. Provide per-project preprocessor options (e.g., _WINSTL_USE_OLD_NAMESPACE) to allow older client code to keep their original namespaces if they chose.
4. Force users of the libraries to change their client code when upgrading to a newer version of the libraries.
5. Move everything to the new namespace and use using declarations [1] to add them to the old namespace. Using using directives (something I'm pathologically opposed to in any case) would not work, since they only make names accessible in a namespace; they do not add names to that namespace (for access from, and qualification by, that namespace externally).
The last option is the most C++-ish but not attractive, as it has a couple of problems. First, having to write using declarations for every construct is a repetitively dull and error-prone activity. Second and (regrettably) most important, one of the STLSoft supported compilers, Visual C++, chokes on this all the way up to (and including) its latest version (Visual C++ .NET 2002) when the constructs being "used" in the old namespace are templates. These two problems render this option unworkable. Furthermore, the technique of overloading via namespace visibility (the third requirement described) only became applicable, and seemed desirable, after I realized the implications of the solution were not supported by this option.
Despite the fact that it does not provide the solution, option 5 did serve to spark the idea sometime later [6] that lead to the solution described here. The concept is extremely simple [7], as can be seen in Listing 2.
The readdir_sequence is no longer defined within the unixstl namespace. It is now in stlsoft::unix_project. Indeed, there is no longer a unixstl namespace at all. In the UNIXSTL root header file unixstl.h, unixstl is defined as an alias for namespace stlsoft::unix_project. (Note this is done only once in a central place, since some older compilers get upset when presented with repeated, albeit identical, namespace alias definitions.)
The implementation of readdir_sequence is simplified, since it now no longer needs to qualify anything from within the stlsoft namespace (so long as there are no identically named constructs in the stlsoft::unix_project namespace, which would "hide" them). This is largely irrelevant to extant classes, but future additions to the libraries of all subprojects will benefit in this way.
But best of all, because unixstl is a full-power alias for stlsoft::unix_project, the client code is completely unchanged; polite but indecisive open-source authors can breath a sign of relief. This technique applies not only to this precise scenario, but also to any other scenario in which namespaces need to be moved around while being courteous of users' desires to not have to rewrite their code.
As always, there is an additional complication, though this is just in respect of the STLSoft libraries (and perhaps not best emulated in your own project's libraries!). Because all libraries were formerly independent, there is a small subset of client code that chose to define _STLSOFT_NO_NAMESPACES [8] and not, say, _XMLSTL_NO_NAMESPACES, which means that the STLSoft project constructs were in the global namespace but the XMLSTL constructs were within the xmlstl namespace. In order to support this, an extra bit of per-processor hackery is necessary, as shown in the extract from xmlstl.h shown in Listing 3. In this circumstance, XMLSTL constructs are actually in the xmlstl namespace, otherwise, they are in stlsoft::xml_project or in the global namespace.
[2] Verbose namespace names are a very good idea, so as to avoid namespace name clashes; that would be a sticky mess!
[3] STLSoft is an open-source organization whose focus is the development of robust, lightweight, and cross-platform STL software; it is located at http://stlsoft.org. It started out as a project to move certain software of my company into the public domain, but is rapidly evolving into a substantial self-contained organization.
[4] STLSoft has a number of subprojects, including ATLSTL, COMSTL, MFCSTL, UNIXSTL, WinSTL, and XMLSTL that provide STL-compliant software for their particular technology. They are located at http://atlstl.org, http://comstl.org, etc.
[5] Large Scale C++ Software Design. John Lakos, Addison-Wesley, 1996.
[6] My family and anyone else with an interest in seeing me portrayed as a normal human being, might be horrified at my admitting that this one came, à la Kekule's benzene snake, in the wee small hours.
[7] Like many good ideas, it seems so obvious after the fact, and one is almost embarrassed for not having thought of it immediately. It is only the fact that a number of people to whom I have illustrated it have also had a "Doh!" moment that I am inclined to write it up as something noteworthy. If the ramifications of namespace aliasing in this context are already obvious to you, I can only apologize for having wasted your time.
[8] These issues are explained at http://stlsoft.org/faq.html.