Hello, and welcome to C++ Weekly. I'm your host, Jason Turner. I'm available for
code reviews and on-site training. In this episode I am going to want to convince you
to stop using 'using namespace', and I'm going to go through why this came up
and why I think it's a good idea for you to stop using it.
First of all, it came up because of this tweet from Will Hawkins back in August 26th of 2021.
Now I did promise Will that I would do an episode about this, and I said it would be four to five
weeks and, well, we're a little bit further out than four to five weeks; but Will says,
"A student called me out today in Intro to C++ for not using 'using namespace std'
at the global scope. Can someone confirm that I am following best practices?"
So let's first show what the student was asking for.
If we take this pretty straightforward, simple "hello world" example where I have
a standard string that has my name in it, and I'm calling "standard cout" to actually
print this out to the console, we can see here I get "Hello Jason."
This student was telling Will that Will had done something bad by not doing this:
Now it is generally considered to be a bad practice actually to do this 'using namespace',
and it has been agreed for quite some
time that you never ever want to put a 'using namespace' in a header file.
Now this, like I said has been agreed for quite some time, and I don't believe there is any
argument about this. If you do have an argument about this, well
go and read everyone else's work on this that has been published for the last several decades;
but if I do this, what I have done is forced the user of my myfile.hpp
to have 'using namespace' have the std namespace in their global scope all the time,
forever. So it's possible that in their company they might have their own, something like this,
string class, that is declared inside their company namespace or whatever; and this becomes
an ambiguity. It's difficult to tell whether I'm referring to the std string or I'm referring to
my company's string. That is not really in question. Let's take this back down to what if
we just do it at the cpp level. So the first thing that I would like to bring up, because this was
brought up in comments in the twitter discussion, is this note from Herb Sutter and Andre
Alexandrescu in the C Coding standards number 59. They say, "Number 59: Don't write "namespace
usings" in a header file or before a #include." So they say you don't want to do something like
this because that can throw off the way that the header file itself works, so they say never do
that; but they do say in short, "You can and should use "namespace using" declarations and
directives liberally in your implementation files after #include directives and feel good about it,
despite repeated assertions to the contrary. "namespace using" declarations and directives are
not evil, and they do not defeat the purpose of namespaces, rather they are what make namespaces
usable." Looks like I have some typos in my transcription of that, but that is not really the
point here. I would like to say that this is an objectively terrible take, and I will back that up
with a few other writings from other people. First of all, I am going to go to the isocpp faq here,
which asks, "Should I use 'using namespace std' in my code?" The answer from the isocpp website,
which, for the record, actually does come originally from Herb Sutter as well,
keeping in mind that C++ Coding Standards book reference that we just made, they say, "Probably
not. People don't like typing "std::" over and over, and they discover that 'using namespace
std' lets the compiler see the 'std' name, even if unqualified. The fly in the ointment is that
it lets the compiler see any 'std' name, even the ones that you don't think about. In other words,
it can create name conflicts and ambiguities." So here's the problem - it can create name conflicts
and ambiguities; and they go on and get some examples here, and they say just "Get over it
and type std::" or use a more explicit using declaration in a very tightly scoped
environment. This is from the Abseil C++ Tips: "Don't use using-directives". Number
153, Tip of the Week - "tl;dr using-directives such as namespace foo are dangerous enough to
be banned by the Google style guide." Now let's be fair, the Google style guide is not
the best C++ style guide, so we don't rely on it for a lot of our tips;
however it does go on to say, "Don't use them in code that will ever need to be upgraded,"
and then it goes on to say, "If you wish to shorten a name, instead use a 'namespace
alias'." It shows some pretty terrible examples of where it's almost impossible to tell
what the code does because of using-declarations here, and I'm going to quote one last bit from
this particular document. It says, "Why do we have this feature, then? There are legitimate
uses of using-directives within generic libraries, but they are so obscure and rare
that they don't deserve a mention here or in the style guide." So this says there are very,
very rare cases where we can use using-directives outside of a small tiny function scope; and
I'll get into, like, the one situation where I think you can use 'using namespace' in a moment;
but now I want to go back to Compiler Explorer and demonstrate some real case for why this could
be a problem. Okay, we're going to write some code that, even with a lot of strict warnings
enabled, I do not expect to generate a warning in any compiler, but we will see.
This code does not generate a warning at all. I am calling this function called 'calculate'. I
am passing a value in. Now granted, this is a little bit more on the side of slideware
and a little bit less like real world code, but it does illustrate the point, I think,
quite effectively. I am getting 4.23 returned because I'm returning 1 x 4.23.
If I pass 2 in here, I'm still getting no warnings, and I get 8.46 being printed
because I am passing in 2 x 4.23. It's exactly as expected. Now let's just say this is in my
handy 'emptycrate' namespace and I had up to this point been calling it something like this, and
you know, I decided, "This is just ridiculous. I shouldn't have to use this all over the place,
so I'm going to go ahead and put in this 'using namespace declaration'."
You know, that's great. Okay, but I'm also including
"some other companies library", and in here they've got
their own 'calculate' function; and we're using company2's library all over the place,
so we just decide it would just make so much more sense if we go ahead and include company2's
namespace also. We just want to do "'using namespace' company2". Now if you are paying
attention you might have noticed that the output of my program changed from 8.26
to 84. Again, no warnings have been generated at all, and even worse, say we have, you know, using
company2's library for quite some time, and then we do an upgrade of it. So we're now in, like,
company2's library version 3, or something like that. We just want to make sure that
version 3 of their library is accessible to us, and in an upgrade, they provide this function.
Now we've just changed the complete meaning of our code in a way that is basically untraceable.
We have no way of knowing that we're now calling a different version of this function
entirely because there was a more appropriate overload found. So if you didn't catch that,
it's because of an implicit conversion from 2, which is a 'literal' to a 'double'. It's a literal
'int' converting it to a 'double' for value, but then when we provide this integer overload,
now this 2 becomes a better match for the integer overload, and that is the one that gets called.
Then, you know, at some point later in the future, maybe we do a cleanup of the code,
and we decide to comment out one of these 'using namespaces' or something, and we could change the
nature of the code in a completely different way. So just don't do this. Besides all of the other
words that everyone else said, and I'll try to remember to put links to all of those in here,
you can so easily create an accidental situation where you are calling a completely different
version of a function than you thought you were, or you accidentally changed the nature of your
program by some upgrade in the future, or by some subtle change to a library in the future,
very difficult to know what went wrong; and this is with -Wconversion enabled in fact,
which I have up here in the upper right corner of the screen. Okay, so when can you use 'using
namespace'? There's a few situations where you might want to do something like this,
and this falls into the category from the Abseil
documentation of saying "in some cases in generic libraries blah, blah, blah,
but it's not even worth mentioning," then it would be something like this.
But that's actually a pretty bad way of doing this as well,
because I've just pulled in everything, and really what I wanted to do was this:
By doing that, now I can
intentionally only pull in the one function that I want overload resolution to work
correctly on. Then the other possibility is for suffixes - string literal suffixes.
Now I can do something like this
where I can give myself a shortcut for creating a string, or for creating a string view, or there's
lots of these in the chrono library. (There is) a set but not used warning. So yes, it's still
compiled. (Uh, just got a warning. I treat it as an error here.) So a few cases, and very confined
local scopes, mostly for the use cases of using the literals that are provided by your library. I
personally don't really like that use case because it feels like a lot of work for something that's
relatively simple unless I'm going to be creating many string views in one particular location,
or in the case where you intentionally want to pull some things in for overload resolution.
Otherwise 'using namespace' is really just far too potentially dangerous. I hope you enjoyed this
episode of C++ Weekly. Be sure to keep learning C++. Give this video a thumbs up if you liked it.