Suppose Alice uses two libraries made by Bob and Charlie.
// This file is written by Alice:
Charlie is now inventing a new feature called foobar , which he adds to his library. foobar great and its users like it. Alice is also starting to use it.
Then Bob says: "I like foobar as well, I want to have my own foobar , which I can use in my library, but I don't want Charlie's dependency." Therefore, he creates his own version.
Oh, oh, now Aliceās code doesnāt compile! Each use of foobar code in Alice's code is ambiguous, and she must rewrite the entire project.
Then the same thing happens next month. And the next month after that.
Now all Alice customers are really unhappy because they are building big technologies and trying to maintain updated versions of their dependencies, but every time they try to update something, Alice code holds on. They make a lot of error messages on their error tracker.
Alice sends a letter to Bob and Charlie and says
You guys should stop doing classes with the same name, otherwise Iāll lose my whole business!
Bob and Charlie send a letter to Alice:
No Alice, you need to stop pasting using namespace bob; and using namespace charlie; into your code. This does not support Bob or Charlie.
Now tell the same story again, except for Charlie. This is just Alice, who does her own classes in her project, encountering new names added by Bob.
In short, the using namespace directive is never a good idea (in my opinion). Especially when the namespace is an external library. You really do not know how this namespace can change in the future, and if it changes in such a way that it is not at all, you will suddenly have a huge mess on your hands.
Using namespace = to reduce namespaces is often a very good idea. I like to do the following:
namespace my_lib { namespace qi = boost::spirit::qi; // Do stuff with qi // ... } // end namespace my_lib
That way I can use the short name qi in my_lib , but I do not impose anything on my users. (Who, as I expect, will not do using namespace my_lib; )
If you are a user, you can do something like
namespace cha = charlie::name::space::is_way_too_long;
But you should be more than happy to type in short namespaces such as bob:: or std:: , regardless of whether you are a user or developer of the library, if this means that your code will not break when the libraries are updated.
This is not about DRY. Putting some kind of qualifier in names greatly simplifies reading your code and understanding what this means.
For example, look at SDL, the popular C library. As far as I know, every macro in SDL starts with SDL_ , and every function starts with SDL_ . Is this a DRY violation? No. There are no duplicated implementation details - a common prefix avoids name clashes. In addition, it makes the code more readable and maintainable - whenever I see a character that speaks of an SDL object, I know it right away. This is very useful for both people and computers.
Room using namespace std; or using namespace my_lib; it seems like choosing one of the best C ++ features and throwing it in the trash. The trade-off is that you can type 5 characters by doing a great deal of damage to readability and maintainability.
Separation of thought: how using namespace affects the quality of error messages you receive.
Here is a simple program that does not compile:
#include <iostream> struct foo {}; int main() { std::cout << foo{} << std::endl; }
When the compiler sees this code, he will have to try every overload of the stream operator that he knows about, and check if foo can be converted to any of these things. Since std::cout is one of the arguments, ADL means that we should look for the entire std . It turns out, unexpected surprise, foo does not convert to any of these things. In gcc 5.3 , the following error message (200 lines) appears.
main.cpp: In function 'int main()': main.cpp:6:13: error: no match for 'operator<<' (operand types are 'std::ostream {aka std::basic_ostream<char>}' and 'foo') std::cout << foo{} << std::endl; ^ In file included from /usr/include/c++/5/iostream:39:0, from main.cpp:1: /usr/include/c++/5/ostream:628:5: note: candidate: std::basic_ostream<_CharT, _Traits>& std::operator<<(std::basic_ostream<_CharT, _Traits>&&, const _Tp&) [with _CharT = char; _Traits = std::char_traits<char>; _Tp = foo] <near match> operator<<(basic_ostream<_CharT, _Traits>&& __os, const _Tp& __x) ^ /usr/include/c++/5/ostream:628:5: note: conversion of argument 1 would be ill-formed: main.cpp:6:20: error: cannot bind 'std::ostream {aka std::basic_ostream<char>}' lvalue to 'std::basic_ostream<char>&&' std::cout << foo{} << std::endl; ^ In file included from /usr/include/c++/5/iostream:39:0, from main.cpp:1: /usr/include/c++/5/ostream:108:7: note: candidate: std::basic_ostream<_CharT, _Traits>::__ostream_type& std::basic_ostream<_CharT, _Traits>::operator<<(std::basic_ostream<_CharT, _Traits>::__ostream_type& (*)(std::basic_ostream<_CharT, _Traits>::__ostream_type&)) [with _CharT = char; _Traits = std::char_traits<char>; std::basic_ostream<_CharT, _Traits>::__ostream_type = std::basic_ostream<char>] operator<<(__ostream_type& (*__pf)(__ostream_type&)) ^ /usr/include/c++/5/ostream:108:7: note: no known conversion for argument 1 from 'foo' to 'std::basic_ostream<char>::__ostream_type& (*)(std::basic_ostream<char>::__ostream_type&) {aka std::basic_ostream<char>& (*)(std::basic_ostream<char>&)}' /usr/include/c++/5/ostream:117:7: note: candidate: std::basic_ostream<_CharT, _Traits>::__ostream_type& std::basic_ostream<_CharT, _Traits>::operator<<(std::basic_ostream<_CharT, _Traits>::__ios_type& (*)(std::basic_ostream<_CharT, _Traits>::__ios_type&)) [with _CharT = char; _Traits = std::char_traits<char>; std::basic_ostream<_CharT, _Traits>::__ostream_type = std::basic_ostream<char>; std::basic_ostream<_CharT, _Traits>::__ios_type = std::basic_ios<char>] operator<<(__ios_type& (*__pf)(__ios_type&)) ^ /usr/include/c++/5/ostream:117:7: note: no known conversion for argument 1 from 'foo' to 'std::basic_ostream<char>::__ios_type& (*)(std::basic_ostream<char>::__ios_type&) {aka std::basic_ios<char>& (*)(std::basic_ios<char>&)}' /usr/include/c++/5/ostream:127:7: note: candidate: std::basic_ostream<_CharT, _Traits>::__ostream_type& std::basic_ostream<_CharT, _Traits>::operator<<(std::ios_base& (*)(std::ios_base&)) [with _CharT = char; _Traits = std::char_traits<char>; std::basic_ostream<_CharT, _Traits>::__ostream_type = std::basic_ostream<char>] operator<<(ios_base& (*__pf) (ios_base&)) ^ /usr/include/c++/5/ostream:127:7: note: no known conversion for argument 1 from 'foo' to 'std::ios_base& (*)(std::ios_base&)' /usr/include/c++/5/ostream:166:7: note: candidate: std::basic_ostream<_CharT, _Traits>::__ostream_type& std::basic_ostream<_CharT, _Traits>::operator<<(long int) [with _CharT = char; _Traits = std::char_traits<char>; std::basic_ostream<_CharT, _Traits>::__ostream_type = std::basic_ostream<char>] operator<<(long __n) ^ /usr/include/c++/5/ostream:166:7: note: no known conversion for argument 1 from 'foo' to 'long int' /usr/include/c++/5/ostream:170:7: note: candidate: std::basic_ostream<_CharT, _Traits>::__ostream_type& std::basic_ostream<_CharT, _Traits>::operator<<(long unsigned int) [with _CharT = char; _Traits = std::char_traits<char>; std::basic_ostream<_CharT, _Traits>::__ostream_type = std::basic_ostream<char>] operator<<(unsigned long __n) ^ /usr/include/c++/5/ostream:170:7: note: no known conversion for argument 1 from 'foo' to 'long unsigned int' /usr/include/c++/5/ostream:174:7: note: candidate: std::basic_ostream<_CharT, _Traits>::__ostream_type& std::basic_ostream<_CharT, _Traits>::operator<<(bool) [with _CharT = char; _Traits = std::char_traits<char>; std::basic_ostream<_CharT, _Traits>::__ostream_type = std::basic_ostream<char>] operator<<(bool __n) ^ /usr/include/c++/5/ostream:174:7: note: no known conversion for argument 1 from 'foo' to 'bool' In file included from /usr/include/c++/5/ostream:638:0, from /usr/include/c++/5/iostream:39, from main.cpp:1: /usr/include/c++/5/bits/ostream.tcc:91:5: note: candidate: std::basic_ostream<_CharT, _Traits>& std::basic_ostream<_CharT, _Traits>::operator<<(short int) [with _CharT = char; _Traits = std::char_traits<char>] basic_ostream<_CharT, _Traits>:: ^ /usr/include/c++/5/bits/ostream.tcc:91:5: note: no known conversion for argument 1 from 'foo' to 'short int' In file included from /usr/include/c++/5/iostream:39:0, from main.cpp:1: /usr/include/c++/5/ostream:181:7: note: candidate: std::basic_ostream<_CharT, _Traits>::__ostream_type& std::basic_ostream<_CharT, _Traits>::operator<<(short unsigned int) [with _CharT = char; _Traits = std::char_traits<char>; std::basic_ostream<_CharT, _Traits>::__ostream_type = std::basic_ostream<char>] operator<<(unsigned short __n) ^ /usr/include/c++/5/ostream:181:7: note: no known conversion for argument 1 from 'foo' to 'short unsigned int' In file included from /usr/include/c++/5/ostream:638:0, from /usr/include/c++/5/iostream:39, from main.cpp:1: /usr/include/c++/5/bits/ostream.tcc:105:5: note: candidate: std::basic_ostream<_CharT, _Traits>& std::basic_ostream<_CharT, _Traits>::operator<<(int) [with _CharT = char; _Traits = std::char_traits<char>] basic_ostream<_CharT, _Traits>:: ^ /usr/include/c++/5/bits/ostream.tcc:105:5: note: no known conversion for argument 1 from 'foo' to 'int' In file included from /usr/include/c++/5/iostream:39:0, from main.cpp:1: /usr/include/c++/5/ostream:192:7: note: candidate: std::basic_ostream<_CharT, _Traits>::__ostream_type& std::basic_ostream<_CharT, _Traits>::operator<<(unsigned int) [with _CharT = char; _Traits = std::char_traits<char>; std::basic_ostream<_CharT, _Traits>::__ostream_type = std::basic_ostream<char>] operator<<(unsigned int __n) ^ /usr/include/c++/5/ostream:192:7: note: no known conversion for argument 1 from 'foo' to 'unsigned int' /usr/include/c++/5/ostream:201:7: note: candidate: std::basic_ostream<_CharT, _Traits>::__ostream_type& std::basic_ostream<_CharT, _Traits>::operator<<(long long int) [with _CharT = char; _Traits = std::char_traits<char>; std::basic_ostream<_CharT, _Traits>::__ostream_type = std::basic_ostream<char>] operator<<(long long __n) ^ /usr/include/c++/5/ostream:201:7: note: no known conversion for argument 1 from 'foo' to 'long long int' /usr/include/c++/5/ostream:205:7: note: candidate: std::basic_ostream<_CharT, _Traits>::__ostream_type& std::basic_ostream<_CharT, _Traits>::operator<<(long long unsigned int) [with _CharT = char; _Traits = std::char_traits<char>; std::basic_ostream<_CharT, _Traits>::__ostream_type = std::basic_ostream<char>] operator<<(unsigned long long __n) ^ /usr/include/c++/5/ostream:205:7: note: no known conversion for argument 1 from 'foo' to 'long long unsigned int' /usr/include/c++/5/ostream:220:7: note: candidate: std::basic_ostream<_CharT, _Traits>::__ostream_type& std::basic_ostream<_CharT, _Traits>::operator<<(double) [with _CharT = char; _Traits = std::char_traits<char>; std::basic_ostream<_CharT, _Traits>::__ostream_type = std::basic_ostream<char>] operator<<(double __f) ^ /usr/include/c++/5/ostream:220:7: note: no known conversion for argument 1 from 'foo' to 'double' /usr/include/c++/5/ostream:224:7: note: candidate: std::basic_ostream<_CharT, _Traits>::__ostream_type& std::basic_ostream<_CharT, _Traits>::operator<<(float) [with _CharT = char; _Traits = std::char_traits<char>; std::basic_ostream<_CharT, _Traits>::__ostream_type = std::basic_ostream<char>] operator<<(float __f) ^ /usr/include/c++/5/ostream:224:7: note: no known conversion for argument 1 from 'foo' to 'float' /usr/include/c++/5/ostream:232:7: note: candidate: std::basic_ostream<_CharT, _Traits>::__ostream_type& std::basic_ostream<_CharT, _Traits>::operator<<(long double) [with _CharT = char; _Traits = std::char_traits<char>; std::basic_ostream<_CharT, _Traits>::__ostream_type = std::basic_ostream<char>] operator<<(long double __f) ^ /usr/include/c++/5/ostream:232:7: note: no known conversion for argument 1 from 'foo' to 'long double' /usr/include/c++/5/ostream:245:7: note: candidate: std::basic_ostream<_CharT, _Traits>::__ostream_type& std::basic_ostream<_CharT, _Traits>::operator<<(const void*) [with _CharT = char; _Traits = std::char_traits<char>; std::basic_ostream<_CharT, _Traits>::__ostream_type = std::basic_ostream<char>] operator<<(const void* __p) ^ /usr/include/c++/5/ostream:245:7: note: no known conversion for argument 1 from 'foo' to 'const void*' In file included from /usr/include/c++/5/ostream:638:0, from /usr/include/c++/5/iostream:39, from main.cpp:1: /usr/include/c++/5/bits/ostream.tcc:119:5: note: candidate: std::basic_ostream<_CharT, _Traits>& std::basic_ostream<_CharT, _Traits>::operator<<(std::basic_ostream<_CharT, _Traits>::__streambuf_type*) [with _CharT = char; _Traits = std::char_traits<char>; std::basic_ostream<_CharT, _Traits>::__streambuf_type = std::basic_streambuf<char>] basic_ostream<_CharT, _Traits>:: ^ /usr/include/c++/5/bits/ostream.tcc:119:5: note: no known conversion for argument 1 from 'foo' to 'std::basic_ostream<char>::__streambuf_type* {aka std::basic_streambuf<char>*}' In file included from /usr/include/c++/5/iostream:39:0, from main.cpp:1: /usr/include/c++/5/ostream:574:5: note: candidate: template<class _Traits> std::basic_ostream<char, _Traits>& std::operator<<(std::basic_ostream<char, _Traits>&, const unsigned char*) operator<<(basic_ostream<char, _Traits>& __out, const unsigned char* __s) ^ /usr/include/c++/5/ostream:574:5: note: template argument deduction/substitution failed: main.cpp:6:20: note: cannot convert 'foo{}' (type 'foo') to type 'const unsigned char*' std::cout << foo{} << std::endl; ^ In file included from /usr/include/c++/5/iostream:39:0, from main.cpp:1: /usr/include/c++/5/ostream:569:5: note: candidate: template<class _Traits> std::basic_ostream<char, _Traits>& std::operator<<(std::basic_ostream<char, _Traits>&, const signed char*) operator<<(basic_ostream<char, _Traits>& __out, const signed char* __s) ^ /usr/include/c++/5/ostream:569:5: note: template argument deduction/substitution failed: main.cpp:6:20: note: cannot convert 'foo{}' (type 'foo') to type 'const signed char*' std::cout << foo{} << std::endl; ^ In file included from /usr/include/c++/5/iostream:39:0, from main.cpp:1: /usr/include/c++/5/ostream:556:5: note: candidate: template<class _Traits> std::basic_ostream<char, _Traits>& std::operator<<(std::basic_ostream<char, _Traits>&, const char*) operator<<(basic_ostream<char, _Traits>& __out, const char* __s) ^ /usr/include/c++/5/ostream:556:5: note: template argument deduction/substitution failed: main.cpp:6:20: note: cannot convert 'foo{}' (type 'foo') to type 'const char*' std::cout << foo{} << std::endl; ^ In file included from /usr/include/c++/5/ostream:638:0, from /usr/include/c++/5/iostream:39, from main.cpp:1: /usr/include/c++/5/bits/ostream.tcc:321:5: note: candidate: template<class _CharT, class _Traits> std::basic_ostream<_CharT, _Traits>& std::operator<<(std::basic_ostream<_CharT, _Traits>&, const char*) operator<<(basic_ostream<_CharT, _Traits>& __out, const char* __s) ^ /usr/include/c++/5/bits/ostream.tcc:321:5: note: template argument deduction/substitution failed: main.cpp:6:20: note: cannot convert 'foo{}' (type 'foo') to type 'const char*' std::cout << foo{} << std::endl; ^ In file included from /usr/include/c++/5/iostream:39:0, from main.cpp:1: /usr/include/c++/5/ostream:539:5: note: candidate: template<class _CharT, class _Traits> std::basic_ostream<_CharT, _Traits>& std::operator<<(std::basic_ostream<_CharT, _Traits>&, const _CharT*) operator<<(basic_ostream<_CharT, _Traits>& __out, const _CharT* __s) ^ /usr/include/c++/5/ostream:539:5: note: template argument deduction/substitution failed: main.cpp:6:20: note: mismatched types 'const _CharT*' and 'foo' std::cout << foo{} << std::endl; ^ In file included from /usr/include/c++/5/iostream:39:0, from main.cpp:1: /usr/include/c++/5/ostream:519:5: note: candidate: template<class _Traits> std::basic_ostream<char, _Traits>& std::operator<<(std::basic_ostream<char, _Traits>&, unsigned char) operator<<(basic_ostream<char, _Traits>& __out, unsigned char __c) ^ /usr/include/c++/5/ostream:519:5: note: template argument deduction/substitution failed: main.cpp:6:20: note: cannot convert 'foo{}' (type 'foo') to type 'unsigned char' std::cout << foo{} << std::endl; ^ In file included from /usr/include/c++/5/iostream:39:0, from main.cpp:1: /usr/include/c++/5/ostream:514:5: note: candidate: template<class _Traits> std::basic_ostream<char, _Traits>& std::operator<<(std::basic_ostream<char, _Traits>&, signed char) operator<<(basic_ostream<char, _Traits>& __out, signed char __c) ^ /usr/include/c++/5/ostream:514:5: note: template argument deduction/substitution failed: main.cpp:6:20: note: cannot convert 'foo{}' (type 'foo') to type 'signed char' std::cout << foo{} << std::endl; ^ In file included from /usr/include/c++/5/iostream:39:0, from main.cpp:1: /usr/include/c++/5/ostream:508:5: note: candidate: template<class _Traits> std::basic_ostream<char, _Traits>& std::operator<<(std::basic_ostream<char, _Traits>&, char) operator<<(basic_ostream<char, _Traits>& __out, char __c) ^ /usr/include/c++/5/ostream:508:5: note: template argument deduction/substitution failed: main.cpp:6:20: note: cannot convert 'foo{}' (type 'foo') to type 'char' std::cout << foo{} << std::endl; ^ In file included from /usr/include/c++/5/iostream:39:0, from main.cpp:1: /usr/include/c++/5/ostream:502:5: note: candidate: template<class _CharT, class _Traits> std::basic_ostream<_CharT, _Traits>& std::operator<<(std::basic_ostream<_CharT, _Traits>&, char) operator<<(basic_ostream<_CharT, _Traits>& __out, char __c) ^ /usr/include/c++/5/ostream:502:5: note: template argument deduction/substitution failed: main.cpp:6:20: note: cannot convert 'foo{}' (type 'foo') to type 'char' std::cout << foo{} << std::endl; ^ In file included from /usr/include/c++/5/iostream:39:0, from main.cpp:1: /usr/include/c++/5/ostream:497:5: note: candidate: template<class _CharT, class _Traits> std::basic_ostream<_CharT, _Traits>& std::operator<<(std::basic_ostream<_CharT, _Traits>&, _CharT) operator<<(basic_ostream<_CharT, _Traits>& __out, _CharT __c) ^ /usr/include/c++/5/ostream:497:5: note: template argument deduction/substitution failed: main.cpp:6:20: note: deduced conflicting types for parameter '_CharT' ('char' and 'foo') std::cout << foo{} << std::endl; ^ In file included from /usr/include/c++/5/bits/ios_base.h:46:0, from /usr/include/c++/5/ios:42, from /usr/include/c++/5/ostream:38, from /usr/include/c++/5/iostream:39, from main.cpp:1: /usr/include/c++/5/system_error:209:5: note: candidate: template<class _CharT, class _Traits> std::basic_ostream<_CharT, _Traits>& std::operator<<(std::basic_ostream<_CharT, _Traits>&, const std::error_code&) operator<<(basic_ostream<_CharT, _Traits>& __os, const error_code& __e) ^ /usr/include/c++/5/system_error:209:5: note: template argument deduction/substitution failed: main.cpp:6:20: note: cannot convert 'foo{}' (type 'foo') to type 'const std::error_code&' std::cout << foo{} << std::endl; ^ In file included from /usr/include/c++/5/string:52:0, from /usr/include/c++/5/bits/locale_classes.h:40, from /usr/include/c++/5/bits/ios_base.h:41, from /usr/include/c++/5/ios:42, from /usr/include/c++/5/ostream:38, from /usr/include/c++/5/iostream:39, from main.cpp:1: /usr/include/c++/5/bits/basic_string.h:5172:5: note: candidate: template<class _CharT, class _Traits, class _Alloc> std::basic_ostream<_CharT, _Traits>& std::operator<<(std::basic_ostream<_CharT, _Traits>&, const std::__cxx11::basic_string<_CharT, _Traits, _Alloc>&) operator<<(basic_ostream<_CharT, _Traits>& __os, ^ /usr/include/c++/5/bits/basic_string.h:5172:5: note: template argument deduction/substitution failed: main.cpp:6:20: note: 'foo' is not derived from 'const std::__cxx11::basic_string<_CharT, _Traits, _Alloc>' std::cout << foo{} << std::endl; ^
Here's the point: If you do using namespace bob; , then each of the bob types, which is streaming, will also be displayed in this list! If you do using namespace charlie; then all its types will be there too!
Not only error messages will be worse, the greater the likelihood that you can get some really bizarre interaction that you did not expect. What if Bob's types are sometimes streams to one of Charlie's types? And are Charlie types sometimes implicitly converted to some standard type that is smooth?
And, of course, all this applies not only to any operator overload, but also to any call to a template or function.
So, on the bottom line, C ++ is much easier to reason about and works much better if you avoid mixing a lot of crap together in the same namespace.