Journal Articles
Browse in : |
All
> Journals
> CVu
> 166
(12)
All > Topics > Programming (877) Any of these categories - All of these categories |
Note: when you create a new publication type, the articles module will automatically use the templates user-display-[publicationtype].xt and user-summary-[publicationtype].xt. If those templates do not exist when you try to preview or display a new article, you'll get this warning :-) Please place your own templates in themes/yourtheme/modules/articles . The templates will get the extension .xt there.
Title: What's in a Namespace?
Author: Administrator
Date: 03 December 2004 13:16:09 +00:00 or Fri, 03 December 2004 13:16:09 +00:00
Summary:
In this article I will visit the mechanics of namespaces and anonymous namespaces and explain how they are used to solve some of the problems associated with linking C++ programs. Then I will move on to explain how they can also be used to provide context.
Body:
In my experience most C++ developers have heard about namespaces. Most of them understand what namespaces are for and the problems they solve. Some even make use of them!
Namespaces can be used for more than preventing name clashes. In this article I will visit the mechanics of namespaces and anonymous namespaces and explain how they are used to solve some of the problems associated with linking C++ programs. Then I will move on to explain how they can also be used to provide context.
The C++ standard has the following description of namespaces:
7.3.0.1 A namespace is an optionally-named declarative region. The name of a namespace can be used to access entities declared in that namespace; that is, the members of the namespace. Unlike other declarative regions, the definition of a namespace can be split over several parts of one or more translation units.
This tells you what a namespace is, but not what one is used for. Consider the following example:
You are writing a COM object that is going to be used to split an input file into a number of output files. For maximum ease of testability and performance you write the actual file processing code in standard C++ and wrap it in a Façade [Façade] called FileSplitter. A COM object can then be written to wrap the file processing FileSplitter class. The COM object provides an interface that forwards to the file processing FileSplitter class.
The COM object client has no knowledge that the COM object is actually just a wrapper, and has no need to know. As far as the client is concerned the COM object is the file splitter. Therefore the obvious name for the COM object class is also FileSplitter (with IFileSplitter the obvious name for the interface).
Having two classes with the same fully qualified name in a C++ program is not permitted. The solution is to introduce namespaces. From Microsoft Visual C++ 7.0 onwards, all COM classes are placed in the ATL namespace (in earlier versions COM classes were required to be in the global namespace). However, although I will use the ATL namespace in this article; and putting COM objects in the ATL namespace is a Microsoft convention, using the name of a technology for a namespace is not usually good practice as it does not provide the right sort of context. For example it would not be sensible or useful to group together all abstract base classes or all classes that implement a recognized pattern.
Due to the limited scope of this example the name for the namespace containing the file processing FileSplitter class is not clear. However, an appropriate name might be something like Process, as the class performs the actual processing of files within the program:
// filesplitter.h namespace Process { class FileSplitter { ... }; }
The file processing FileSplitter class can then be used by fully qualifying its name in the COM class:
// filesplitter_com.h #include "filesplitter.h" namespace ATL { class FileSplitter : public IFileSplitter { ... private: Process::FileSplitter impl_; }; };
Both classes can now happily coexist in the same program, despite the fact that they have the same name, as they are both in different namespaces. The namespaces also help to make maintenance easier by providing local context for each class.
The C++ standard has the following to say about anonymous (or unnamed) namespaces:
7.3.1.1 An unnamed-namespace-definition behaves as if it were replaced by
namespace unique{ /* empty body */ } using namespace unique; namespace unique { namespace-body }where all occurrences of unique in a translation unit are replaced by the same identifier and this identifier differs from all other identifiers in the entire program. (Although entities in an unnamed namespace might have external linkage, they are effectively qualified by a name unique to their translation unit and therefore can never be seen from any other translation unit.)
This is an even less useful description than the one for regular namespaces. Bjarne Stroustrup has the following to say about unnamed namespaces in The C++ Programming Langue [TCPPPL]:
It is often useful to wrap a set of declarations in a namespace simply to protect against the possibility of name clashes. That is, aim to preserve locality of code rather than to present an interface for users...
In this case we can simply leave the namespaces without a name...
Clearly, there has to be some way of accessing members of an unnamed namespace from the outside. Consequently, an unnamed namespace has an implied using-directive...
...In particular unnamed namespaces are different in different translation units. As desired, there is no way of naming a member of an unnamed namespace from another translation unit.
This gets much closer to what an anonymous namespace is for, but is still not as clear as it could be. Mark Radford was kind enough to supply me with the following description and examples of the use of anonymous namespaces:
Designers of C++ programs often encounter a need for some declarations to have Translation Unit (TU) scope. For example, consider the encapsulation of database access using SQL: it may well make sense for the SQL strings to be encapsulated within the TU in which the database access is implemented.
Having declared identifiers for string constants within a TU, the designer has another issue to resolve: what if the same identifier is used in another TU? Without support from the C++ language, it may not be possible to guarantee avoiding this situation, without telling other people what identifiers have been used. Putting it another way: without language support, such encapsulated identifiers are not really encapsulated.
In early C++ the solution was one inherited from C: declare identifiers as static to give them internal linkage. However, already this has the drawback of overloading the keyword static. Also, as the language evolved and templates were added, it became apparent there was another drawback: identifiers with internal linkage could not be template arguments.
To resolve the above issues, a more C++-centric solution was devised - the unnamed namespace, or as it tends to be called in more common parlance, the "anonymous namespace". Identifiers declared in the anonymous namespace have external linkage (and can be used as template arguments), but are accessible only in the TU in which they are declared. The mechanism by which this is achieved is implementation dependent, but a popular approach is the use of a scheme where the compiler mangles the identifier name with that of the TU.
The descriptions in the C++ standard and The C++ Programming Language, together with the comments from Mark Radford cover the importance and uses of anonymous namespaces well. Not only do they prevent name clashes, they also provide context. The reader of a source file (.cpp) knows that anything located within the anonymous namespace is only intended for use within that translation unit and no other.
Namespaces do not only provide solutions to the problems associated with linking C++ programs. They can also provide context that helps a developer determine a class's, a function's or a variable's position and purpose within a program just from looking at a single source file.
Before describing the mechanics of namespaces in The C++ Programming language, Stroustrup has the following to say about them:
A namespace is a mechanism for logical grouping. That is, if some declarations logically belong together according to some criteria, they can be put in a common namespace to express the fact….
So, namespaces are also about grouping related elements of a program together. The file splitter example above can be expanded to demonstrate this. Suppose your program not only splits files, but can also merge them.
Again, the standard C++ processing code should be wrapped in a façade class (FileMerger) and should be separate from the COM class. The processing class processes files and therefore belongs in the Process namespace along with Process::FileSplitter.
// filesplitter.h namespace Process { class FileSplitter { ... }; } // filemerger.h namespace Process { class FileMerger { ... }; }
The FileMerger COM class, of course, goes into the ATL namespace with ATL::FileSplitter.
Elements that are grouped together by a namespace share a context. Equally, when you look at a single class, function or variable declaration you know what context it is in from its namespace.
For example, you could open any source or header file from the example above and be looking at a FileSplitter or FileMerger class and know immediately whether it was a file processing class or a COM class, just from its namespace. This is a significant maintenance advantage as you would not have to go searching through other source and header files trying to determine the context of the file you had just opened.
There are, of course, other ways of providing this context. Some, such as directory structure, complement the use of namespaces very well, but is a subject beyond the scope of this article.
Appending File to the front of FileSplitter and FileMerger suggests that there can be other types of splitters and mergers within the context of the program. Otherwise, they may as well just be called Splitter and Merger. In the example presented so far that would be perfectly reasonable.
However, now consider that as well as splitting complete files, record by record, the records themselves are split in some way. The logical name for a class that splits a record is RecordSplitter. This introduces a new context and should really introduce a new namespace:
// recordsplitter.h namespace Process { namespace Record { class Splitter { ... }; } }
If a record merging class is introduced into the program that too would go into the Record namespace. The file processes should also be placed in a nested namespace:
// filesplitter.h namespace Process { namespace File { class Splitter { ... }; } } // filemerger.h namespace Process { namespace File { class Merger { ... }; } }
This technique can of course be taken too far and is probably overkill for this example, but I hope it shows the concept of namespaces providing context.
What about anonymous namespaces? Do they provide context too? Absolutely! Anonymous namespaces provide context within a translation unit. As stated above, they tell you that the contents of the anonymous namespace are only intended for use in the current translation unit.
Consider the following example. You have a lookup table of postcodes that are to be loaded from a database:
// Postcode.cpp #include "lookup\postcode.h" namespace PostcodeTools { namespace { const std::string postcodeSql = "SELECT postcode FROM postcodes"; } void Postcode::Load() { dbConn_->Execute( ... ); ... } ... }
There are a number of things that can be done with the postcodeSql string. It could be a local variable inside the load function, but it may be something that changes if the database table moves or is renamed for some reason. Therefore it should be as prominent as possible to make finding it easy. This would suggest it should be brought out to namespace scope so that it is near the top of the file. This opens up the possibility of a name clash (although const variables actually have internal linkage) as other translation units containing the namespace PostcodeTools, could also have a postcodeSql member also.
The obvious solution is to place postcodeSql in an anonymous namespace as shown. Even though members of an anonymous namespace have external linkage, they cannot clash with names declared in other translation units. The anonymous namespace also tells you that the postcodeSql string is only intended for use within the source file.
In this article I have examined the use of namespaces and anonymous namespaces and the context provided by them. I hope I have made a good case for their usage and that I have encouraged readers to use namespaces more widely and for context as well as for preventing name clashes.
Notes:
More fields may be available via dynamicdata ..