Click here to Skip to main content
15,891,204 members
Articles / Programming Languages / C++
Article

Using namespaces properly

Rate me:
Please Sign up or sign in to vote.
3.84/5 (15 votes)
30 Jan 2001 125.2K   51   15
This article does not teach you the syntax of namespaces. Rather, it shows you how to use them properly.

Introduction

Namespaces are a very powerful C++ language feature. This article does not teach you the syntax of namespaces. Rather, it shows you how to use them properly.

Namespaces simply wrap all enclosed names with another name. For example:

namespace net {
    class Socket {
        ...
    };
}

...

net::Socket socket;

By doing that, they make sure that if two libraries both implement the Socket class, if they name their namespaces differently your program can use both without a conflict.

But this brings up another question: If two independent companies both decide to write network libraries, what are the chances that they are going to implement a class named Socket? My guess is somewhere around 100 percent.

We also like it when namespace names are easy to type, which means that they should be 2-4 characters long. With that in mind, what are the chances that both companies are going to name their namespace net? 5 percent? 10 percent?

Whatever it is, it shows that namespaces do not solve the problem, they only make it less severe.

An Industrial Strength Solution

The solution to this problem is to use long, unique namespace names, and then bring the namespaces into a program by using short aliases.

So a company writing the network library should write something like:

namespace net_33843894 {
    class Socket {
        ...
    };
}

where the number after net_ is going to be generated using a random number generator. Say this code is placed in a header file called <netlib>

Then the library is sold to a client, who decides to use it on a project. The client then writes his own project-local header file named <mynetlib>, with the following content:

#include <netlib>

namespace net = net_33843894;

He has just created a project-local alias for the namespace of his library vendor. If the namespace name net had already been taken by another library, the user can choose another name: net2, sock, or something else. There will be no name conflicts.

Lowering Barriers

A smart thing to do with your library is to make it easy for people to start using it. In an ideal world, they should be able to double-click on an installation file and the library would be immediately available inside their development environment. Next thing they are typing is #include <yourlib> and they are using it to do something useful.

However, if the user has to make his own header for every header in your library, then he has to suffer a little bit in order to use it. Not every user will be willing to do so.

The solution to this problem is to provide reasonable defaults, but to let the users cop out of them if they are not suitable. The way to do this is with preprocessor directives in your header file:

namespace net_33843894 {
    class Socket {
        ...
    };
}

#ifndef NO_NET_33843894_ALIAS
    namespace net = net_33843894;
#endif

This way, we provide a reasonable default for the namespace name. If that name is already taken, then the user can define the macro NO_NET_33843894_ALIAS and no alias will be defined.

Current Compilers

Error messages are already a nightmare with templates. With long namespace names, we make them even worse.

Unfortunately, none of the compilers I use are smart enough to display an error with the shortest available namespace alias at the point of error. So even though you may be using the alias net, if you make an error using the Socket class the error will mention net_33843894::Socket. Not very readable.

So I use a little trick. It works only for headers that contain only inline functions (as it affects the actual names used by the linker), but I have plenty of those. If the macro NO_NET_33843894_ALIAS is not defined, I use the short name as the namespace name, and the long name as the alias:

#ifdef NO_NET_33843894_ALIAS
namespace net_33843894 {
#else
namespace net {
#endif
    class Socket {
        ...
    };
}

#ifndef NO_NET_33843894_ALIAS
    namespace net_33843894 = net;
#endif

And the error messages become bearable again.

 

For more good stuff about C++, including a way to write code without memory errors, visit http://www.jelovic.com.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
Yugoslavia Yugoslavia
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
GeneralNO!! Don't do this! Just use nested namespaces. Pin
Don Clugston29-Mar-04 12:50
Don Clugston29-Mar-04 12:50 
GeneralRe: NO!! Don't do this! Just use nested namespaces. Pin
AndreRyan29-Feb-08 17:03
AndreRyan29-Feb-08 17:03 
GeneralRe: NO!! Don't do this! Just use nested namespaces. Pin
Member 368078527-Jan-09 11:08
Member 368078527-Jan-09 11:08 
Sorry, but I agree with the original poster (Dejan). In fact, I think the decision to include nested namespaces in C++ (or C# for that matter) was a bad one.

The original intention of namespaces (as Dejan notes) was to allow developers from different organizations to contribute parts of a single codebase without their identifiers conflicting. If everyone in an organization puts their code in a single namespace, and its name is sufficiently unique, then I enjoy this benefit of namespaces (i.e. each piece of code doesn't conflict with anyone else's code).

But it's difficult for me to see the benefit of extending this to a hierarchy. The original distinction that led to namespaces - the distinction between code coming from different organizations - isn't hierarchical. (You're either outside my organization or you're not; even if you're in a different department we ought to be able to cooperate on naming.)

Beyond that, I think dangerous things happen when a single development shop starts using hierarchical namespaces internally. For example, suppose you put your "SocketHelper" class in namespace "OurOrg_12357::Helpers::IO" and I put my own "SocketHelper" class in "OurOrg_12357::Helpers::IO::Net". We're much less likely to find out that we've both coded classes called SocketHelper than if we'd both simply used "OurOrg_12357." And since we're really in the same organization, we don't want that name collision hidden. We probably want to know about the fact that we've both written a "SocketHelper."

Unfortunately, just about everyone I've ever worked with who knew about namespaces tended to try to use them as an organizational tool. Something just feels wrong to them about putting everything in "OurOrg_12357," as if that we're somehow comparable to putting all of their files in C:\. The difference is that the file system was constructed with a different purpose than namespaces. MS-DOS 2.0 did not introduce folders so that people from other companies could put stuff on your C-drive.

Of course (and as Dejan pointed out) another big problem with namespaces like "OurOrg_12357::Helpers::IO" is that they clutter up some already very cluttered error messages. I agree wholeheartedly with that sentiment, although (again) I don't find my colleagues to be universal on this point. I think I know quite a few developers who would argue that if you find template-related error messages (or generic-related error messages in C#) to be complex, then you just don't understand templates (or generics). I don't agree with that; my feeling is that the human factor (misunderstanding or plain stupidity) needs to be ruled out as much possible in the design of a computer language just like it is in the design of other man-machine interfaces.

I think these misconceptions (or at least disagreements) fall into a category that might reasonably be called the "common sense" anti-pattern. By that I mean that too many design decisions are made because they resemble other (seemingly similar) design decisions. That is, they have the look-and-feel of good software engineering practice without actually _being_ good software engineering practice. Namespaces were made hierarchical simply because so many other things in CS legitimately are, or need to be, hierarchies (classes, file systems, etc.)

It must have felt like simple common sense to the C++ committee that namespaces should be hierarchies... unfortunately, common sense frequently does not apply to CS. After all, the ability to program is by no means "common" among the general populace. A related rule of mine is that I treat absolute statements about CS or even programming with extreme skepticism.

I think these disagreements are also examples of another anti-pattern (which might be called the "kitchen sink" anti-pattern) that legitimizes the addition of features to a language based on the argument that they can be ignored by those who don't like them. I don't like hierarchical namespaces, but there's no way I can ignore them. Any time a potential collision is squelched by a colleague's decision to use some goofy, deeply-nested namespace, then an opportunity for collaboration with that colleage is lost - regardless of my decision to simply use the top-level organizational namespace.

C++ exemplifies this "kitchen sink" anti-pattern fairly well (having been designed by a committee) but .NET is the absolute champ. Anything that even remotely resembles a good idea (e.g. functional programming) ends up being embraced by the ever-expanding .NET moniker. C++ had a bad tendency to introduce keywords with each revision... C# has a nasty tendency to introduce whole new paradigms.Thumbs Down | :thumbsdown:
GeneralGreat article for newbies - idea for extension... Pin
Paul Evans12-Dec-02 10:35
Paul Evans12-Dec-02 10:35 
GeneralA better solution to your problem Pin
17-May-01 14:05
suss17-May-01 14:05 
GeneralRe: A better solution to your problem Pin
Dejan Jelovic18-May-01 2:21
Dejan Jelovic18-May-01 2:21 
GeneralHELP ME PLS!!!!!!!!!!!!!!! Pin
7-May-01 6:01
suss7-May-01 6:01 
GeneralRe: HELP ME PLS!!!!!!!!!!!!!!! Pin
7-May-01 6:45
suss7-May-01 6:45 
GeneralRe: HELP ME PLS!!!!!!!!!!!!!!! Pin
ekolis8-Jul-12 13:03
ekolis8-Jul-12 13:03 
GeneralHELP ME PLS!!!!!!!!!!!!!!! Pin
7-May-01 6:01
suss7-May-01 6:01 
GeneralRe: HELP ME PLS!!!!!!!!!!!!!!! Pin
1-Jun-01 9:47
suss1-Jun-01 9:47 
GeneralAn alternative to a random number Pin
Jason De Arte31-Jan-01 8:53
Jason De Arte31-Jan-01 8:53 
GeneralRe: An alternative to a random number -- not really Pin
Dejan Jelovic31-Jan-01 10:37
Dejan Jelovic31-Jan-01 10:37 
GeneralSuggestion: URNs as namespace identifiers Pin
Jonathan Gilligan31-Jan-01 13:30
Jonathan Gilligan31-Jan-01 13:30 
GeneralRe: Suggestion: URNs as namespace identifiers Pin
Dejan Jelovic18-May-01 2:31
Dejan Jelovic18-May-01 2:31 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.