Namespaces

In this article we discuss about named and un-named namespaces and inline namespaces. We also discuss how an un-named namespace is a better alternative for giving internal linkage in comparison to the static keyword.

Last Reviewed and Updated on February 7, 2020
Posted by Parveen(Hoven),
Aptitude Trainer and Software Developer

My C/C++ Videos on Youtube

Here is the complete playlist for video lectures and tutorials for the absolute beginners. The language has been kept simple so that anybody can easily understand them. I have avoided complex jargon in these videos.

We have seen that scope describes boundaries within which a name is visible. Programming languages have borrowed this concept from the real life world where we have boundaries of countries, of cities, and of what not? Names of family members are scoped to the house in which they live. When we address our family members we do not say, "Sam of House No. 37, how was the school today?" Our phone numbers are scoped to our country, we do not have to dial an ISD prefix each time we call someone in another state of our country. Scoping allows us to re-use names, prevent name clashes. The same phone number can be present in different countries. Many Sams can co-exist in the same city.

In previous chapters we have seen that when the static keyword is applied on a global variable its scope is restricted to its containing file. This means we have two partitions - either the current file or the global un-shielded playground. But if we want more of them? - as many as we like? The answer lies in the concept of namespaces.

The namespace Syntax

A namespace is created with a syntax similar to the one used for writing a struct. The keyword namespace is used for this purpose. Below is the code that creates a namespace ns. The semi-colon at the end of the closing brace is optional.

namespace ns
{
    int i;
}; // semi-colon is optional
 
int main()
{
    return 0;
}

The global identifiers, those that are not a part of any namespace, are treated as being in a sort of an implicit namespace, many would like to call it the default or global namespace. The "int main" function, for example, is[and always must be] in the global namespace. The global namespace can be partitioned into logical partitions by using the namespace keyword. In the above code we have two partitions - "ns" and the global free space. We can see the power of this concept through the following code, where three int i are living happily in the same file, and any number of them could still be accommodated without problems, by creating more namespaces!

namespace ns
{
    int i;
};
 
namespace ns1
{
    int i;
};
 
namespace ns2
{
    int i;
};
 
int main()
{
    return 0;
}

I have clubbed "main" with the namespace definitions above; it's only for clarity. The right place for defining namespaces is explained later in this article.

namespace Spanning

A namespace declaration of the same name can be present at more than one places, within the same file, or within different files of the same project. The compiler "joins" all the parts during pre-processing so that all the different parts coalesce into one. In the code below the namespace ns is split into three blocks. When pre-processing occurs, they are merged into one, under the same name, ns. So you have a good flexibility in fragmenting your namespace and spread them into different locations.

namespace ns
{
    int i;
};
 
namespace ns
{
    int j;
};
 
namespace ns
{
    int k;
};
 
int main()
{
    return 0;
}

A namespace can span multiple files also. So a namespace with the same name can be present in one header file of your project, and it can also be present in another file of your project. The namespace called "std" is declared in numerous headers of the standard C++ kit.

Where to put Namespaces?

As a good programming practice, all namespaces should be declared inside headers only. Below is an example of a namespace containing a function declaration. This code should be put inside a header file. There is nothing new in doing this. Global function declarations are otherwise also supposed to be put in header files. And, when they are written inside a namespace, the namespace has to go there as well.

namespace ns
{
    void fx();
};

The definition of the above function should appear in a translation unit. Full path of the function has to appear at the time of definition, like as shown below.

#include "myheader.h"
using namespace std;
 
void ns::fx()
{
    cout << "Hello" << endl;
}

Take another example.Following is a header file that contains a struct definition. The struct contains a function declaration.

#ifndef MY_HEADER
#define MY_HEADER
 
#include <iostream>
 
namespace ns
{
    struct SMyStruct
    {
        int i;
 
        void gx();
 
    };
}
 
#endif

The definition of the function fx can be given inside a .cpp file like shown below. Notice that the definition is not to be put inside the namespace boundaries. Namespaces are not declared inside cpp files.

#include "myheader.h"
 
using namespace std;
 
void ns::SMyStruct::gx()
{
    cout << i << endl;
}

Next, let's see the case of global variables inside a namespace. A variable such as, int x, should be declared with an extern declaration. It's definition should be put inside a translation unit, again the full path should be specified. See the code below for how to put a global identifier inside a header file. No memory is being allocated for x, we are merely declaring, and introducing, its existence by using the extern keyword.

#ifndef MY_HEADER
#define MY_HEADER
 
#include <iostream>
 
namespace ns
{
    extern int x;
}
 
#endif

The definition of x appears in a translation unit like this. Again notice that the namespace name is used to qualify the full path, and the variable hasn't been put inside namespace braces, same as was the case with function definitions.

#include "myheader.h"
 
using namespace std;
 
int ns::x = 89;

This variable can be accessed from elsewhere in the project. This is how it could be accessed from main, for instance.

#include "myheader.h"
 
using namespace std;
 
int main()
{
    cout << ns::x << endl;
 
    return 0;
} 

We have used cout numerous times. It is also declared with the extern keyword. It appears inside the std namespace. This is how it appears effectively -

namespace std
{
    extern ostream cout;
    .... others like cin, cerr, etc,
};

There is one exception to the above rule, but that is an obvious one. Unnamed namespaces should appear only in translation units because they are used for giving internal linkage[file scoping] to the contained variables. We have already discussed that an un-named namespace is a better option for doing this, as compared to the use of the static keyword.

The using Directive

Consider the code below where we have crossed out the directive: using namespace std; When this directive is not used, then the names within std have to be qualified to pre-pend full paths. Notice below the full paths for cout and endl. If the names are not qualified, a compiler error would occur.

using namespace std;

int main()
{
    std::cout << "Hello World !" << std::endl;

    return 0;
}

The using directive can be used to "open" names appearing within a namespace. This declaration comes handy when you are using several identifiers in a translation unit, and all of them belong to the same namespace, like we have been doing for cin, cout, endl and string, all of which belong to the same namespace, std.

The using directive allows us to open any number of namespaces in a file. But this could potentially lead to conflicts. Take for instance, a namespace ns that contains two identifiers p and q. Also, take another namespace ns2 that contains two identifiers p and r - the identifier p being in common. If we open both the namespaces with the directives as shown below, then any use of the name p would lead to an ambiguity; the compiler would ask: who's p, of ns or ns2?

using namespace ns;
using namespace ns2

The conflict could be avoided by selectively opening only fewer names out of a namespace. In the above case, we could open q from ns and r from ns2, by writing the using declaration as below.

using ns::q;
 
using ns2::r;
 
int main()
{
    cout << r << endl;
 
    cout << q << endl;
 
    // p from ns is not "opened"
    // full namespace path needed
    cout << ns::p << endl;
 
    // here also, full path
    cout << ns2::p << endl;
 
    return 0;
}

The using directives and declarations should not be put in header files, because when these header files get included into a number of translation units and through complex paths, the namespaces could un-expectedly "open up", leading to bugs very difficult to trace. Use these directives only in the .cpp files, the place where they are meant to be used.

Nested Namespaces

A namespace can be contained inside another namespace. The inner namespace is called the nested namespace. The code below nests a namespace called ns2 inside a namespace called ns. The nested namespace can access the members of the outer namespace without qualification - full path need not be specified. So i can be accessed in ns2 without any qualification. But the converse is not true. Qualification is required when the inner members are accessed from the outer namespace, like for y as shown below.

namespace ns
{
    int i = 8;
 
    namespace ns2
    {
        // ns2 can access members
        // of parent without qualification
        int y = i;
    }
 
    // ERROR
    int k = y;
 
    // CORRECT
    int p = ns2::y;
}

There doesn't seem to be any purpose for using nested namespaces in C++. The sole purpose of creating namespaces in C++ was to prevent name clashes, which can be very easily handled by non-nested namespaces because there are no practical limits on the number of namespaces that you can create in a project. In fact, the Standard C++ Library uses just the namespace std, without nesting any namespaces inside it, even though many developers feel that nesting would have led to a more organized structure. The general view is that namespaces are not for organizing your code. They are for preventing name clashes. Code can be organized by using properly named header files and translation units, and by also using nested classes and structs.

The syntax for nesting a namespace is a bit bulky because we need to repeat the curly braces for deeper nestings. Future versions are considering a simpler syntax, like the one known to C# and Java developers:

namespace ns::ns1::ns2
{ 
    ... 

} 

Inline Namespaces

Inline namespaces have been introduced in C++11. An inline namespace is a nested namespace, but its members are treated as members of the outer namespace. In the following code the namespace nsInline is an inline namespace of nsOuter. It's member, i, can be accessed as if it were a member directly inside nsOuter.

namespace nsOuter
{
    namespace nsInner
    {
        int i = 99;
    }
    
    inline namespace nsInline
    {
        int i = 56;
    }
}
 
int main() 
{
    cout << nsOuter::i << endl;
}

When a new feature is added to a Standard, it certainly has a use, and use scenarios. New features are added only after extended discussions and reviews. Let me give you a use case for the inline namespaces. I am keeping it extremely simple so that you can get a feel of the whole point. Suppose there is function fx in a library. The function is declared in some header file like this.

namespace ns
{
    inline namespace ns10
    {
        void fx();    
    }
}

And, the definition of this function appears inside a translation unit like this -

#include "..."
using namespace std;

void ns::ns10::fx()
{
    cout << "fx version 1.0" << endl;
}

And, the world uses it like this.

int main() 
{
    ns::fx();
    
    return 0;
}

What happens when a newer version of this function is issued? With the same signature, but with changes to internal implementation? This new version will render the previous version inaccessible, because there can be present only one definition of a function[signature same] in one project. So either your end users lose the older version, or you have to create a function with a different name. The latter would break the whole source code, leading to maintenance problems. This situation can, however, be avoided by using an inline namespace. Below is the re-written header file. Notice how we have moved the inline keyword to ns20 now, exposing it instead.

namespace ns
{
    namespace ns10
    {
        void fx();    
    }
    
    inline namespace ns20
    {
        void fx();    
    }
}

The definitions in the cpp file are written like this. The new version of fx can even call its older version, if that is required for the DRY principle.

void ns::ns10::fx()
{
    cout << "fx version 1.0" << endl;
}
 
void ns::ns20::fx()
{
    // if required, a call to
    // fx version 1.0 can 
    // also be inserted here
    ns::ns10::fx();
    
    cout << "fx version 2.0" << endl;
}

The end user can now use both the versions in his main function.

int main() 
{
    // newer version
    ns::fx();
    
    // older version available too
    ns::ns10::fx();
}

Namespace Aliases

A namespace alias can be used to give a shorter name to a longer path. The following code demonstrates this. An alias is created for a long path, ending at namespace nsC. The alias doesn't create a new namespace; it's just an abbreviation that saves typing.

namespace ns
{
    namespace nsA
    {
        namespace nsB
        {
            namespace nsC
            {
                int y = 99;
            }
        }
    }
}
 
// alias
namespace nsX = ns::nsA::nsB::nsC;
 
int main() 
{
    cout << nsX::y << endl;
}

Anonymous Namespaces

Un-named namespaces are also called anonymous namespaces.They are written inside translation units to give internal linkage to identifiers, restricting their visibility to the current file only. They should be preferred to the use of static keyword for this purpose.



static int ii;

static void ffx();

// same thing with an anonymous
// namespace
namespace 
{
    int i;

    void fx()
    {

    }
}

How does the compiler achieve internal linkage through an un-named namespace? The compiler gives a project wide unique name[and known only to itself] to the un-named namespace. It also adds a using directive for the same namespace at the top of that translation unit, so that the un-named namespace variables get un-qualified access within that file. The unique name given by the compiler is known to the compiler only[it knows the names you have used, so it can act smarter], and so, there is only one namespace by that name in the entire project, effectively hiding the contained identifiers from other translation units.



Creative Commons License
This Blog Post/Article "Namespaces" by Parveen (Hoven) is licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License.
Updated on 2020-02-07. Published on: 2015-12-02