Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Rationale behind using namespace behavior

Quote from the standard:

A using-directive specifies that the names in the nominated namespace can be used in the scope in which the using-directive appears after the using-directive. During unqualified name lookup (3.4.1), the names appear as if they were declared in the nearest enclosing namespace which contains both the using-directive and the nominated namespace.

Look at this code:

namespace A {

    int fn() { return 1; }

}

namespace Inner {

    int fn() { return 2; }

    namespace B {

        using namespace A;

        int z = fn();

    }

}

Here, before I knew the exact rules of namespaces, I had expected that z will be initialized to 1, as I written using namespace A, so expected that A::fn() will be used. But it is not the case, z will be initialized to 2, as Inner::fn() is called because of the rule I quoted.

What is the rationale behind this behavior: "as if they were declared in the nearest enclosing namespace which contains both the using-directive and the nominated namespace"?

What would be the cons, if using namespace worked as applying using declarations for everything in that namespace?

Note: this is the related issue that motivated me to ask this question.

like image 902
geza Avatar asked Jul 04 '17 18:07

geza


People also ask

What is the purpose of using namespaces?

Namespaces are used to organize code into logical groups and to prevent name collisions that can occur especially when your code base includes multiple libraries.

Is it good to use using namespace std?

The statement using namespace std is generally considered bad practice. The alternative to this statement is to specify the namespace to which the identifier belongs using the scope operator(::) each time we declare a type.

What is the purpose of using namespace std in C++?

In C++, a namespace is a collection of related names or identifiers (functions, class, variables) which helps to separate these identifiers from similar identifiers in other namespaces or the global namespace. The identifiers of the C++ standard library are defined in a namespace called std .


1 Answers

A desirable property of a namespace system is that of what I call incremental API compatibility. That is, if I add a symbol to a namespace, then any previously working program should keep working and mean the same thing.

Now, plain C++ with overloads is not incrementally API compatible:

int foo(long x) { return 1; }

int main()
{
    foo(0);
}

Now I add the overload int foo(int x) { return 2; } and the program silently changes meaning.

Anyway, when C++ people designed the namespace system they wanted that when incrementing an external API, previously working code should not change the namespace from where the symbol is chosen. From your example, the previous working code would be something like:

namespace A {
    //no fn here, yet    
}

namespace Inner {

    int fn() { return 2; }

    namespace B {

        using namespace A;
        int z = fn();
    }
}

And z is easily initialized to 2. Now augmenting namespace A with a symbol named fn will not change the meaning of that working code.

The opposite case does not really apply:

namespace A {
    int fn() { return 1; }
}

namespace Inner {

    // no fn here

    namespace B {

        using namespace A;
        int z = fn();
    }
}

Here z is initialized to 1. Of course, if I add fn to Inner it will change the meaning of the program, but Inner is not an external API: actually, when Inner was written initially, A::fn did already exist (it was being called!), so there is no excuse for being unaware of the clash.


A somewhat practical example

Imagine this C++98 program:

#include <iostream>

namespace A {
int move = 0;
void foo()
{
    using namespace std;
    cout << move << endl;
    return 0;
}
}

int main()
{
    A::foo();
    return 0;
}

Now, if I compile this with C++11, everything works fine thanks to this using rule. If using namespace std worked as applying using declarations for everything in that namespace, then this program would try to print function std::move instead of A::move.

like image 171
rodrigo Avatar answered Nov 15 '22 05:11

rodrigo