On C++ namespaces

by Tomas Restrepo

Introduction

Since it's creation by Bjarne Stroustrup, C++ has undergone extensive changes, specially in more recent years by the C++ Standards Committee. Several new features have been added to the basic language, including templates, exception handling, run time type information, and, of course, namespaces.

You might be inclined to believe that namespaces don't affect you one way or another unless you decide to use them, but they do. The C++ Standards Committee has basically rewritten the Standard Library, placing most of its facilities inside a namespace called std. This change alone forces changes in existing pre-draft programs that use the SL.

But, What's a namespace, really?

A namespace defines a new scope. Members of a namespace are said to have namespace scope. They provide a way to avoid name collisions (of variables, types, classes or functions) without some of the restrictions imposed by the use of classes, and without the inconvenience of handling nested classes.

Defining a namespace is similar to defining a class. First goes the namespace keyword, followed by the identifier (the namespace name), followed by member declarations enclosed in braces. For example:


namespace direct {
  class Arrow
  {
  public:
    Arrow(int dir);
    void  setDirection(int dir);
  private:
    int   direction;
  }
  // ...... other stuff
}

A namespace, however, cannot have access specifiers, such as public: or private:. All members of a namespace are public. It cannot have a trailing semicolon, either. An important difference between classes and namespaces, is that class definitions are said to be closed, meaning that, once defined, new members cannot be added to it. A namespace definition is open, and can be split over several units. For example:


// file SY.h
namespace SY {
  class Maker { ... };
  class SuperMaker : public Maker { ... };
}

// file  data.h
namespace SY {
  class Binder { ... };
  class DataBinder : public Binder { ... };
}

In this example, there are two files (SY.h and data.h), both defining namespace SY. The definition of SY on data.h does not conflict with the one in SY.h, but actually extends it. If you look closely at the Standard Library, you'll notice that no single header file declares all members of namespace std. Each file only declares some members, adding them to the global std namespace.

Using Namespaces

There are four ways you can refer to namespace members:

Unnamed Namespaces

Until now, I've only covered named namespaces, but you can also declare unnamed namespaces. Take for example:


  namespace
  {
    class Car
    {
      .... // class members here
    }
    // other members here
  }

this definition behaves exactly like:


  namespace __UniqueName__
  {
    class Car
    {
      .... // class members here
    }
    // other members here
  }
  
  using namespace __UniqueName__;

For each unnamed namespace, the compiler generates a unique name (represented here by __UniqueName__), which differs from every other name in the program. You might be asking yourself, What's the use of this?

Let's see the example above. Class Car is defined in an unnamed namespace declared at global scope, thus, it can be referred to as if it were declared directly at global scope. However, since it's a member of an unnamed namespace, the compiler mangles its name with the generated namespace name, so it won't conflict with other names.

Unnamed namespaces can also be defined inside other namespaces. Suppose the unnamed namespace in the example above was declared inside namespace foo. Then class Car could be referred to as foo::Car. Notice there's no mention of the unnamed namespace, but the link name for Car will still be mangled with namespace foo and the unique name generated for the unnamed namespace by the compiler.

An interesting use of unnamed namespaces is hiding names inside modules. Before, this would be done using the static keyword, but the new C++ Standard reads in section 7.3.1.1 Unnamed Spaces, paragraph 2:

"The use of the static keyword is deprecated when declaring objects in a namespace scope, the unnamed namespace provides a superior alternative."

In case you've forgotten (or didn't know), static, when applied at namespace scope, specifies internal linkage. However, static only applies to names of objects, functions and anonymous unions, not to type declarations.

Personally, I feel that, while unnamed namespaces are a far better solution than static to this problem, it's not the best that could have been implemented. To me, using unnamed namespaces in this way seem to be too much like taking advantage of a "side" effect of the lack of name of the namespace. I would feel much more comfortable with an appropriately named keyword to accomplish this behavior (think hidden or internal), but then again, I'm no language lawyer, nor am I completely informed of the reasons why the committee chose it that way.

Conclusion

Namespaces are a powerful addition to an already powerful language, giving the programmer more flexibility, provided he knows how to take advantage of it. Please consider the use of namespaces carefully when planning your next project, you might be surprised at how useful they can be.