An actual example where 'using namespace' causes problems

J

Juha Nieminen

A relatively large open source C++ project suffered of a sudden problem
when trying to compile the program on Visual Studio 2010: The program
wouldn't compile because there were ambiguous definitions of 'shared_ptr'.

As you might guess, this project uses the boost library and liberally
uses "using namespace std;" and "using namespace boost;" everywhere, and it
so happens that VS2010 has an implementation of std::shared_ptr of the
upcoming C++ standard.

In principle it's completely ok if two libraries use the same name for
something, as long as they do it inside their respective namespaces. After
all, that's exactly what namespaces exist for in the first place. Naturally
because of this any decent C++ book/tutorial warns about the dangers of
writing 'using namespace', as it may produce naming conflicts.

Well, here's an *actual* concrete example which happened in practice.
 
M

Marcel Müller

Juha said:
As you might guess, this project uses the boost library and liberally
uses "using namespace std;" and "using namespace boost;" everywhere, and it
so happens that VS2010 has an implementation of std::shared_ptr of the
upcoming C++ standard.

Well, as long as you do not completely operate in your own namespace
there is always a risk of upcoming name clashes. But always using full
qualified names makes the code not really more readable and writable.
However you may still use qualified names where the clashes exist.

Maybe you should switch to importing the classes as needed like Java
does with newer IDEs. This should prevent you from further surprises
without blowing up the code too much.


Marcel
 
Ö

Öö Tiib

  A relatively large open source C++ project suffered of a sudden problem
when trying to compile the program on Visual Studio 2010: The program
wouldn't compile because there were ambiguous definitions of 'shared_ptr'..

  As you might guess, this project uses the boost library and liberally
uses "using namespace std;" and "using namespace boost;" everywhere, and it
so happens that VS2010 has an implementation of std::shared_ptr of the
upcoming C++ standard.

  In principle it's completely ok if two libraries use the same name for
something, as long as they do it inside their respective namespaces. After
all, that's exactly what namespaces exist for in the first place. Naturally
because of this any decent C++ book/tutorial warns about the dangers of
writing 'using namespace', as it may produce naming conflicts.

  Well, here's an *actual* concrete example which happened in practice.

Yes, i also prefer "using std::string", "using std::cout", "using
std::endl". It is longer to type but also it documents better what i
want to use from large namespace in current translation unit. As
result the clashes are less likely and simpler to repair.
 
B

Bo Persson

Marcel said:
Well, as long as you do not completely operate in your own namespace
there is always a risk of upcoming name clashes. But always using
full qualified names makes the code not really more readable and
writable.

That's arguable. If you try it, you will soon get used to reading
std::names easily.
However you may still use qualified names where the
clashes exist.

A problem is that if you have unqualified names in the code, how do
you know which qualified name the original author actually meant? How
do you know that you are adding the correct qualifier?


Bo Persson
 
M

Marcel Müller

Bo said:
That's arguable. If you try it, you will soon get used to reading
std::names easily.

.... as long as they are that short and as long as they still fit on my
screen.

In practice the screen size (in both dimensions) has always been an
issue to me when using modern languages, even without full qualified
names. And I talk about UXGA.

And think of third party namespaces (libraries or so). They should not
use that short names, otherwise the risk of name clashes only moves from
the identifier to the namespace.

A problem is that if you have unqualified names in the code, how do
you know which qualified name the original author actually meant? How
do you know that you are adding the correct qualifier?

The context of the last working platform is a pretty good guess. It
should never fail.


Marcel
 
J

Juha Nieminen

Marcel Müller said:
But always using full
qualified names makes the code not really more readable and writable.

I disagree. Here's a good example:

What can you tell me about this line of code?

if ( equal(a, b, c) )

That's right. Basically nothing. There's a conditional, and in the
condition some kind of function, or maybe a macro (or even maybe a
functor or even a constructor) is being called and some variables are
given to it as parameters. It's impossible to say what the types of
these variables might be. You would have to study quite some amount of
the rest of the code in order to know what this line means, and it might
be difficult if it's not immediately obvious where 'equal' might be
defined. (A sufficiently smart IDE might help with that, but those are
not always available, nor should code comprehensibility rely on such
tools.) You might *guess* which "equal()" is being used, but it would
still just be a guess. It might well be something else completely.

In contrast, assume that the line of code would have been written as:

if ( std::equal(a, b, c) )

Now this is a whole different thing altogether. The little 'std::' prefix
makes a whole world of a difference.

Even if you didn't know 'std::equal()', you would at least immediately
know where to look for reference. And if you already know what 'std::equal()'
does, it also tells you a lot about what that line of code is doing, and
even what kind of variables the parameters are (iow. some kind of
iterators).

The 'std::' prefix makes the code less ambiguous and easier to understand.
Why would anybody outright oppose its usage goes beyond my comprehension.
 
K

Keith H Duggar

  I disagree. Here's a good example:

  What can you tell me about this line of code?

    if ( equal(a, b, c) )

  That's right. Basically nothing. There's a conditional, and in the
condition some kind of function, or maybe a macro (or even maybe a
functor or even a constructor) is being called and some variables are
given to it as parameters. It's impossible to say what the types of
these variables might be. You would have to study quite some amount of
the rest of the code in order to know what this line means, and it might
be difficult if it's not immediately obvious where 'equal' might be
defined. (A sufficiently smart IDE might help with that, but those are
not always available, nor should code comprehensibility rely on such
tools.) You might *guess* which "equal()" is being used, but it would
still just be a guess. It might well be something else completely.

  In contrast, assume that the line of code would have been written as:

    if ( std::equal(a, b, c) )

  Now this is a whole different thing altogether. The little 'std::' prefix
makes a whole world of a difference.

  Even if you didn't know 'std::equal()', you would at least immediately
know where to look for reference. And if you already know what 'std::equal()'
does, it also tells you a lot about what that line of code is doing, and
even what kind of variables the parameters are (iow. some kind of
iterators).

The 'std::' prefix makes the code less ambiguous and easier to understand..
Why would anybody outright oppose its usage goes beyond my comprehension.

Probably you haven't written enough generic code to realize that
explicit qualification breaks ADL (Argument Dependent Lookup aka
Koenig lookup).

Suppose a, b, and c are user defined types in some namespace and
in said namespace is an overloaded equal function that "does the
right thing" for a, b, and c but better that std::equal. What do
you say now?

This in the form of the swap function, is a classic example that
has been discussed before and at length. Tt is one motivation to
write using declarations (not directives!) such as

using std::equal ;

instead of explicit qualification if one is writing generic code
to allow ADL and/or detect ambiguities.

KHD
 
J

James Kanze

Probably you haven't written enough generic code to realize
that explicit qualification breaks ADL (Argument Dependent
Lookup aka Koenig lookup).

Perhaps more significantly, using an explicit qualifier means
that the name is *not* dependent, no matter what arguments are
used.

Of course, if you're writing generic code, and you want to call
std::equal (and not some silly function with the same name in
some user namespace), then this is what you want.

Which means, of course, that this is a rather strong argument in
favor of using explicit qualifiers, at least in generic code.
(I favor them everywhere, but in generic code, they're
absolutely essential if you want to be sure your code works.)
Suppose a, b, and c are user defined types in some namespace
and in said namespace is an overloaded equal function that
"does the right thing" for a, b, and c but better that
std::equal. What do you say now?

That the programmer who implemented some particularly efficient
version of std::equal without specializing the version in std::
is incompetent.
This in the form of the swap function,

The classic form of the swap function implements a
specialization of std::swap. Take a look at any of the
containers in the standard library, for example.
 
K

Keith H Duggar

Perhaps more significantly, using an explicit qualifier means
that the name is *not* dependent, no matter what arguments are
used.

Of course, if you're writing generic code, and you want to call
std::equal (and not some silly function with the same name in
some user namespace), then this is what you want.

Some "silly" function? Yeah I guess the Boost designers must be
"silly" because, for just one example, they put swap /overloads/
into namespace boost for the unordered containers instead of
specializing std::swap.

Of course, the reason they did this is because it is /impossible/
to "specialize" std::swap for user-defined generic containers.
Which means, of course, that this is a rather strong argument in
favor of using explicit qualifiers, at least in generic code.

No, it is an argument for you not fully understanding the issue.
(I favor them everywhere, but in generic code, they're
absolutely essential if you want to be sure your code works.)

They are absolutely not essential if you want to be sure your
generic code works.
That the programmer who implemented some particularly efficient
version of std::equal without specializing the version in std::
is incompetent.

So Boost programmers are incompetent?
The classic form of the swap function implements a
specialization of std::swap.

Since partial specialization of functions does not exist in C++,
instead the equivalent is an /overload/, and since it is illegal
to overload std functions, it is impossible to "specialize"
std::swap for user defined template classes.

Therefore, when the topic is generic programming (as my topic
was) your advice is non-sense.
Take a look at any of the
containers in the standard library, for example.

Take a look at Boost or probably any other decently designed
/generic/ non-std library to see many examples of such "silly"
code written by those "incompetent" programmers. Then maybe
you can teach us all how to do it right.

KHD
 
J

Juha Nieminen

Keith H Duggar said:
This in the form of the swap function, is a classic example that
has been discussed before and at length. Tt is one motivation to
write using declarations (not directives!) such as

using std::equal ;

instead of explicit qualification if one is writing generic code
to allow ADL and/or detect ambiguities.

Note that there's a significant difference (in terms of readability and
otherwise) between:

#include <algorithm>
using namespace std;
...
// 300 lines later:
template<typename T>
void foo(T a, T b, T c)
{
if ( equal(a, b, c) )
...
}

and:

#include <algorithm>
...
// 300 lines later:
template<typename T>
void foo(T a, T b, T c)
{
using std::equal;
if ( equal(a, b, c) )
...
}

A "using std::something" might be justifiable in some cases, but even then
for clarity it should be close to the usage of the name so that the code
becomes self-documenting and easier to understand.

Of course in your specific example it's a question of opinion whether one
should even have to be aware of what a function does internally, because
that exposes internal implementation details.
 
Ö

Öö Tiib

  Note that there's a significant difference (in terms of readability and
otherwise) between:

      #include <algorithm>
      using namespace std;
      ...
      // 300 lines later:
      template<typename T>
      void foo(T a, T b, T c)
      {
          if ( equal(a, b, c) )
          ...
      }

and:

      #include <algorithm>
      ...
      // 300 lines later:
      template<typename T>
      void foo(T a, T b, T c)
      {
          using std::equal;
          if ( equal(a, b, c) )
          ...
      }

No one really advocates the first example, it is written often just to
shorten examples. For translation unit it is fine if implemented like
that:

#include <algorithm>
using std::equal;
// ...
// 300 lines later:
template<typename T>
void foo(T a, T b, T c)
{
if ( equal(a, b, c) )
// ...
}
}

The using declaration documents that there is planned to be used equal
  A "using std::something" might be justifiable in some cases, but even then
for clarity it should be close to the usage of the name so that the code
becomes self-documenting and easier to understand.

  Of course in your specific example it's a question of opinion whether one
should even have to be aware of what a function does internally, because
that exposes internal implementation details.

Someone may write some sort of joke::equal or funny::sort that does
not follow the interface requirements of std::equal or std::sort. If
he does so then most likely he will be beaten badly by review/team and
avoid doing it ever again. Fearing that nonstd::equal may be made to
open browser and load some pronsite therefore feels like being too
paranoid. It is after all a bug like operator= that doing odd things
is a bug. Can not forbid operator= or demand that it is always used
fully qualified? One should trust the team.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,770
Messages
2,569,583
Members
45,074
Latest member
StanleyFra

Latest Threads

Top