Let's assume, Bob has wrapped his library into the namespace "bob", and Alice is going to make the whole namespace visible inside her own function by a single "using namespace bob", instead of "using bob::XYZ" for every single item:
// This file is written by Alice:
#include <iostream>
// She uses Bobs library:
#include "bob.hpp"
int main(void) {
// Import Bobs library and use it:
using namespace bob;
unsigned short value = 50000;
bob::dump_as_signed(value);
// Should not be possible without std:: prefix:
cout << "foobar" << endl;
}
On the other hand, Bob tried to prevent such scenarios by wrapping the implementation inside a dummy namespace, and making only these symbols available, which are intended for other users:
// This file is written by Bob
#include <iostream>
#include <type_traits>
// Namespace for public use:
namespace bob {
// Implementation details:
namespace impl_ {
// Visible ONLY within sub-namespace:
using std::cout;
using std::endl;
using std::is_integral;
using std::make_signed;
// No repeated std:: prefixes at all:
template <typename T,
typename S = typename make_signed<T>::type>
void dump_as_signed(const T i) {
static_assert(is_integral<T>::value, "no integer");
// Do something very very useful:
cout << "signed:" << static_cast<S>(i) << endl;
}
}
// Make available without poisoning with std::*:
using impl_::dump_as_signed;
}
Because of all using directives are wrapped into a dummy "impl_" namespace within Bobs major namespace, there is no risk for Alice to accidently import symbols from the std:: namespace, too.
So, my questions are:
- I don't like that there is a dummy namespace for implementation details, which is "theoretically" visible for everybody. Is there a nicer way, to be able to use many symbols from for e. g. std:: without leaking these AND without prefixing every symbol explicit with std::? (I'm also thinking about generated API-Docs, which show "bob::impl_::XYZ" instead of "bob::XYZ".)
- I think, it is not very DRY to repeat std:: a. s. o. again and again everywhere. I also understand that a relatively global "using namespace std" inside a larger scope (such as a class) isn't that beautiful, but hundreds of std:: prefixes are much uglier, in my opinion. Aside from poisoning problems: Which do you think is nicer, and WHY? Or got a completely different idea?
OK, I hope my question is clear. Thanks for reading! :)
Let's suppose that Alice is using two libraries, made by Bob and Charlie.
Now, Charlie invents a new feature called
foobar
which he adds to his library.foobar
is great and his users like it. Alice starts using it also.Then Bob says, "I like
foobar
also, I want to have my ownfoobar
I can use in my library. But I don't want a dependency on Charlie." So he creates his own version.Uh oh, now Alice's code doesn't compile! Every usage of
foobar
in Alice's code is ambiguous and she has to rewrite her whole project.Then, the same thing happens next month. And the next month after that.
Now, all of Alice's customers are really unhappy because they are building large technologies and trying to keep up-to-date versions of their dependencies, but every time they try to upgrade anything, Alice's code craps out. They make a lot of bug reports on her bug tracker.
Alice sends an email to Bob and Charlie and says
Bob and Charlie send an email back to Alice:
Now, let's tell the same story again, except there is no Charlie. It's just Alice making her own classes in her project, colliding with new names added by Bob.
In short, a
using namespace
directive is never a good idea (in my opinion). Especially when the namespace is an external library. You don't really know how that namespace can change in the future, and if it changes in a way that is at all bad for you, you suddenly have a huge mess on your hands.Using
namespace =
to shorten namespaces is often a very good idea. I like to do the following:That way I get to use the short name
qi
inmy_lib
, but I don't impose anything on my users. (Who I expect will not be doingusing namespace my_lib;
!)If you are a user, you could do something like
But, you should be more than happy to type short namespaces like
bob::
orstd::
, whether you are a user or a library implementor, if it will mean that your code doesn't break when the libraries are upgraded.This is not about DRY. Putting some kind of qualifier on names makes it much easier to read your code and understand what it means.
For instance look at SDL, a popular C library. To my knowledge, every macro in SDL begins
SDL_
and every function beginssdl_
. Is that a violation of "DRY"? No. There are no duplicated implementation details here -- the common prefix is there to avoid name collisions. Also, it makes the code more readable and maintainable -- whenever I see a symbol that is talking about an SDL entity I know so immediately. It's very helpful to both the humans and the computers.Putting
using namespace std;
orusing namespace my_lib;
is like taking one of C++ best features and throwing it in the garbage. The trade-off is, save yourself typing 5 characters, at the cost of making a great harm to readability and maintainability.Parting thought: How does
using namespace
affect the quality of the error messages that you get.Here's a simple program that doesn't compile:
When the compiler sees this code, it is going to have to try every stream operator overload that it knows about and check if
foo
is convertible to any of those things. Becausestd::cout
is one of the arguments, ADL means that we have to search the entirestd
namespace. Turns out, surprise surprise,foo
isn't convertible to any of those things. Ongcc 5.3
I get the following (200 line) error message.Here's the point: If you do
using namespace bob;
, then every one ofbob
's types that is streamable is also going to appear in that list! If you dousing namespace charlie;
then all of his types will be there too!Not only will the error messages be worse, there's a greater chance that you can get some really bizarre interaction that you didn't expect. What if Bob's types are occasionally streamable into one of Charlie's types? And Charlie's types are occasionally implicitly convertible to some standard type that is streamable?
And of course this all applies not just to any operator overload, but any template or function call.
So, bottom line, C++ is a lot easier to reason about and works a lot better if you avoid mixing lots of crap together in one namespace.