Cppcoreguidelines: NL.n Don't pollute global namespace with 'using namespace'

Created on 7 Sep 2016  ·  18Comments  ·  Source: isocpp/CppCoreGuidelines

I think it is generally considered good practice to not pollute global namespace with using statements (particularly std). But I think people do it often.

There are a number of issues where people are talking about this: #497 and #723.

There more complex rules that people are suggesting but this simple, uncontroversial rule that I think could be enforced easily.

declined

Most helpful comment

The problem with adding using namespace std even in a local scope is that
when new symbols are added to std your program could stop working.

On Sat, Feb 11, 2017 at 10:53 AM, Bjarne Stroustrup <
[email protected]> wrote:

A possible case for namespace directives in a header: a header designed
specifically to synthesize an environment from a variety of libraries. Has
this been seen in the wild? Opinions?


You are receiving this because you are subscribed to this thread.
Reply to this email directly, view it on GitHub
https://github.com/isocpp/CppCoreGuidelines/issues/725#issuecomment-279154493,
or mute the thread
https://github.com/notifications/unsubscribe-auth/AC3mPHpfDwaTWCsOIoUj2h6tTcd8Lsd1ks5rbdlqgaJpZM4J2tj-
.

--
Michael
(617) 899-1723

All 18 comments

Is the standard library a special case here? In small applications of a few hundred lines, it's perfectly acceptable to use namespace std.

We already have SF.7 with regards to not using namespaces in header files.

I think the universally agreed upon rule is to not use using namespace in global scope in header files. Anything more strict will usually be subject to exceptions, although it is my impression that the rule suggested here by KrisTC is also widely applied (outside of toy/teaching examples)

Would it be too strict to suggest not to put _anything_ in the global namespace from a header file? That would include all _using_ directives, declarations and any other symbol? I suppose an alternative would be to suggest that anything that can go in a namespace, should go in a namespace when it comes to headers.

This issue has been very quiet.

I like @MikeGitb's description. I universally agreed upon rule is correct for people who think about it, but I still find people do it all the time in our company. A rule that the checker could enforce would be good.

I worry that @galik's suggestion, although good, could not work for too many people. There is loads of existing (old) code that does not use namespaces. The major codebase in our company uses COM/MIDL compiler and so we use prefix all our types. I suspect there are lots of libraries doing this. MFC / ATL, etc...

However globally removing a namespace should be banned :)

I see nothing wrong about using namespace directives in implementation files. A .cpp is a local scope. Andrew's example of "using namespace std" in a small program is an example. Why litter an implementation with hundreds of std:: and other My_foundation_library:: in code where std and My_foundation_library are ubiquitous? I wouldn't do that for a library that was used only in a few places; in such cases the X:: helps find those few places. Should we have a rule suggesting that?

A possible case for namespace directives in a header: a header designed specifically to synthesize an environment from a variety of libraries. Has this been seen in the wild? Opinions?

The problem with adding using namespace std even in a local scope is that
when new symbols are added to std your program could stop working.

On Sat, Feb 11, 2017 at 10:53 AM, Bjarne Stroustrup <
[email protected]> wrote:

A possible case for namespace directives in a header: a header designed
specifically to synthesize an environment from a variety of libraries. Has
this been seen in the wild? Opinions?


You are receiving this because you are subscribed to this thread.
Reply to this email directly, view it on GitHub
https://github.com/isocpp/CppCoreGuidelines/issues/725#issuecomment-279154493,
or mute the thread
https://github.com/notifications/unsubscribe-auth/AC3mPHpfDwaTWCsOIoUj2h6tTcd8Lsd1ks5rbdlqgaJpZM4J2tj-
.

--
Michael
(617) 899-1723

Another way to look at it is that by "using namespace X" you get what the designer of X intended you to get when using X. If something is added to X, your code might break (and even that might be good) or it might improve.

I see nothing wrong with using namespace directives in .cc files at global scope, so long as you're in a codebase that doesn't make use of the global namespace. That list of requirements is long enough that I worry about people being able to follow the rules responsibly, and so we (Google) are still holding to "no using directives, ever."

  • If you add a using directive (or even just a using declaration) in a header, you're polluting some set of namespaces for everyone that transitively includes that header. (This is well understood.)
  • If you add a using directive in a local scope or a local namespace, it doesn't work the way that most people think it does. It is not the same as "enumerate all of the symbols in that namespace and using-declare them in this scope" - it's more like "find the nearest common ancestor of the current scope and the target namespace, and add all of the items from the target namespace to that ancestor." In codebases that have extensive nesting and complex namespace structure (foo::bar::baz importing from std::chrono, for example), this often means "add stuff to the global namespace". Any of the intermediate namespaces are then places where additions can cause breakages: adding to foo, or foo::bar, or foo::bar::baz, std::, or the global namespace. (I seem to recall some additional subtleties around ADL that are also worrisome.)

On the one hand, I'm starting to come around to allowing limited use of using directives for particular namespaces at global scope (std, or the namespace for most of our internal utility code). On the other hand, there's so many things that can go wrong ... it's at most annoying to have chatty std::'s floating around, but it can be actively harmful for a long-lived codebase to get any of this wrong. All of which is why I recommend the Guideline be a little chatty and set a good example - implicit endorsement of using directives for namespace std is a more slippery slope than most people recognize.

Do you see any harm in putting using std::string;, for example, near the
top of a .cc file?
That is, using the few specific symbols you actually care about.

On Mon, Feb 13, 2017 at 12:05 PM, Titus Winters notifications@github.com
wrote:

I see nothing wrong with using namespace directives in .cc files at global
scope, so long as you're in a codebase that doesn't make use of the global
namespace. That list of requirements is long enough that I worry about
people being able to follow the rules responsibly, and so we (Google) are
still holding to "no using directives, ever."

  • If you add a using directive (or even just a using declaration) in a
    header, you're polluting some set of namespaces for everyone that
    transitively includes that header. (This is well understood.)
  • If you add a using directive in a local scope or a local namespace,
    it doesn't work the way that most people think it does. It is not
    the same as "enumerate all of the symbols in that namespace and
    using-declare them in this scope" - it's more like "find the nearest common
    ancestor of the current scope and the target namespace, and add all of the
    items from the target namespace to that ancestor." In codebases that have
    extensive nesting and complex namespace structure (foo::bar::baz importing
    from std::chrono, for example), this often means "add stuff to the global
    namespace". Any of the intermediate namespaces are then places where
    additions can cause breakages: adding to foo, or foo::bar, or
    foo::bar::baz, std::, or the global namespace. (I seem to recall some
    additional subtleties around ADL that are also worrisome.)

On the one hand, I'm starting to come around to allowing limited use of
using directives for particular namespaces at global scope (std, or the
namespace for most of our internal utility code). On the other hand,
there's so many things that can go wrong ... it's at most annoying to have
chatty std::'s floating around, but it can be actively harmful for a
long-lived codebase to get any of this wrong. All of which is why I
recommend the Guideline be a little chatty and set a good example -
implicit endorsement of using directives for namespace std is a more
slippery slope than most people recognize.


You are receiving this because you commented.
Reply to this email directly, view it on GitHub
https://github.com/isocpp/CppCoreGuidelines/issues/725#issuecomment-279454808,
or mute the thread
https://github.com/notifications/unsubscribe-auth/AC3mPEQvhv_6Dxd9XHNA_4-miMBERcJmks5rcI1igaJpZM4J2tj-
.

--
Michael
(617) 899-1723

Very little harm - that behaves in the ways people generally expect, and even for codebases that don't have good indexing tools, it's generally not hard to grep around and figure out what type is being used when there are local declarations like that.

In the specific case of the standard library types, I find it a little icky - contrary to the idea expressed above, I find that it's reasonably likely for some random local project to have a local vector or map or string, and leaving the std:: makes it clear to the reader that there's nothing tricky going on. So I personally recommend in code review to avoid doing so, but that's not a pattern I'd force on others. Merely a suggestion/preference.

@tituswinters: I'm aware of the odd definition of using namespace but so far I wasn't aware of any particular unexpected problems that would cause (I'm only a hobby programmer, so I have only very little experience with large codebases). Could you share an example?

The problems are largely variations on "something got added to a namespace I imported." This can result in build breaks (if this causes collisions between names in the namespace you import into), but that's basically the best case - if you have near-match APIs you can wind up adding an API to a far-away namespace, have it picked up because of a using-directive, and selected as a better-match overload, potentially changing the behavior of the calling code arbitrarily.

Basically: if you're writing code that lives in isolation or has no expected maintenance (nothing it depends on is going to change for the lifetime of your code), a using-directive is fine. That is: if your code works, it works. But if change is possible, codebase scale and lifespan increase the risk of using-directives doing something surprising. If it's limited to a .cc, it's easy to fix, but if it's in a header you can be in a situation that's extremely expensive to fix.

The problem I see with using namespace std; is when C has size_t and std also has size_t which can result in a collision of types and even namesas the compiler might not know weather you meant std::size_t or C's size_t.

Here is an perfect example even namespace collisions (using experimental filesystem and boost filesystem as an example):

#include <iostream>
#include <boost/filesystem.hpp>
#include <experimental/filesystem>
using namespace std::experimental;
// Will compile Error because the filesystem namespace is not only in boost but also in
// std::experimental. And if that does not generate an Error a line below will.
using namespace boost; 

int main(int argc, char* argv[]) {
    // Will fore sure Compile Error because both namespaces have all of this.
    std::cout << filesystem::path(argv[0]).filename().string()<< std::endl;
    return 0;
}

The filesystem::path(argv[0]).filename().string() actualy simulates doing basename(argv[0]) on Linux in a much more multiplatform way that is not bound to linux at all.

Regarding the size_t example: Is there wording in the standard that requires size_t to be the same as std::size_t? Because I never had a conflict between c and c++.

The collision between boost and std is probably much more common, but so far I never had any urgings to add using namespace boost to any file for exactly that reason (and the massive scope of that namespace). You don't even have to go to std::experimental. Dozens of types have made it from boost into the std namespace over the years (bind, shared_ptr,...)

size_t and std::size_t are the same type so that collision is impossible.

It seems the most common name collision I see beginners running into on the online forums is against std::count. Most recent StackOverflow example (less than a day ago) IntelliSense: “count” is ambigous

Added examples to SF.6

Was this page helpful?
0 / 5 - 0 ratings

Related issues

RedDwarf69 picture RedDwarf69  ·  3Comments

jeffreylindsey picture jeffreylindsey  ·  5Comments

larsch picture larsch  ·  4Comments

HowardHinnant picture HowardHinnant  ·  3Comments

beinhaerter picture beinhaerter  ·  5Comments