FREE Subscription to Dr. Dobb’s Digest: Same Great Content, New Digital Edition
Site Archive (Complete)
C++
Email
Print
Reprint

add to:
Del.icio.us
Digg
Google
Furl
Slashdot
Y! MyWeb
Blink
April 01, 2004
Flexible Implementations Without Using Directives

Matthew Wilson
It is widely accepted that using directives are an unacceptable part of the public interface of library code. This is because a using directive indiscriminately makes visible all symbols within the referenced namespace from the point of directive declaration, raising the potential for symbol clash (which is what namespaces were created to circumvent).
Flexible Implementations Without Using Directives

Where debate does exist, however, is regarding the use of using directives in the implementation of library or application code. Proponents acknowledge that you shouldn't do it in your headers, but suggest that it is, if not good, at worst benign in implementation files. This epitomizes a philosophy of doing no harm to others, but not impinging on one's right to balance risks for oneself.

The desire to use using directives in this context comes from two motivations. The first is convenience—you may call it laziness, I couldn't possibly comment—since if you use using declarations or explicitly qualify every symbol, you have a lot more typing. Consider the following block of code, which uses using declarations.

// with using declarations

using winstl::performance_counter;
using winstl::findfile_sequence;

void measure_interval(. . .)
{
  performance_counter                counter;
  findfile_sequence                  sequence("*.*");
  findfile_sequence::const_iterator  begin = sequence.begin();
  findfile_sequence::const_iterator  end   = sequence.end();

  for(counter.start(); begin != end; ++begin)
  {
    . . .
  }
  counter.stop();

. . .
If each symbol from the winstl namespace is explicitly qualified, this takes the more verbose form.
// with explicit qualification

void measure_interval(. . .)
{
  winstl::performance_counter                counter;
  winstl::findfile_sequence                  sequence("*.*");
  winstl::findfile_sequence::const_iterator  begin = sequence.begin();
  winstl::findfile_sequence::const_iterator  end   = sequence.end();

. . .
The minimum amount of typing is by making use of using directives:
// with using directives

using namespace winstl;

void measure_interval(. . .)
{
  performance_counter                counter;
  findfile_sequence                  sequence("*.*");
  findfile_sequence::const_iterator  begin = sequence.begin();
  findfile_sequence::const_iterator  end   = sequence.end();

. . .
I have my own opinions on this motivation, but I'd be inviting a religious war to comment further than saying that it is not compelling. The second motivation—flexibility—carries a lot more weight. A claimed advantage to the using directive form is that if and when one wishes to replace the constructs from the current namespace with those from another, it is a simple one-line change. For example, suppose we wish to port our code to UNIX, using synonymous constructs from the unixstl namespace.
// with using directives

#ifdef WIN32
using namespace winstl;
#elif defined(unix)
using namespace unixstl;
# . . .

void measure_interval(. . .)
{
. . .
With the other two approaches, there would be a lot more typing, as in:
// with using declarations

#ifdef WIN32
using winstl::performance_counter;
using winstl::findfile_sequence;
#elif defined(unix)
using unixstl::performance_counter;
using unixstl::findfile_sequence;
# . . .
or
// with explicit qualification

#ifdef WIN32
  winstl::performance_counter                counter;
  winstl::findfile_sequence                  sequence("*.*");
  winstl::findfile_sequence::const_iterator  begin = sequence.begin();
  winstl::findfile_sequence::const_iterator  end   = sequence.end();
#elif defined(unix)
  unixstl::performance_counter               counter;
  unixstl::findfile_sequence                 sequence("*.*");
  unixstl::findfile_sequence::const_iterator begin = sequence.begin();
  unixstl::findfile_sequence::const_iterator end   = sequence.end();
# . . .
Naturally, very few people would choose to write code such as the latter form. More likely, they would define their own preprocessor symbol to substitute the namespace name in light of platform discrimination, as in:
#ifdef WIN32
# define THE_NS   winstl
#elif defined(unix)
# define THE_NS   unixstl

. . .

  THE_NS::performance_counter                counter;
  THE_NS::findfile_sequence                  sequence("*.*");
  THE_NS::findfile_sequence::const_iterator  begin = sequence.begin();
  THE_NS::findfile_sequence::const_iterator  end   = sequence.end();
But we know that use of the preprocessor is depreciated in C++, and is to be avoided wherever possible [4]. Hence, we can say that the explicit qualification and using declaration approaches are robust (namespace symbol visibility and use is selective, and under explicit programmer control) but inflexible, whereas the using directives approach is flexible (usually only one change is needed) but less robust. This is true as far as it goes, but using directives is a big sledgehammer to crack what is actually a very small nut. There is a solution that is as robust as explicit qualification and using declarations, and as flexible and convenient as using directives. In a previous article [5], I described a simple but very useful application of the technique of namespace aliasing [6] for facilitating flexibility in effecting benign changes to open-source header files. Namespace aliasing can also be applied here to address our implementation flexibility problem. The discriminated namespace is aliased to an independent symbol, which may then be used for using declarations or for explicit qualification. Any necessary platform discrimination is significantly simplified and localized. According to your own tastes you can elect to use either of two variants, with using declarations:
// with using declaration and namespace aliasing

#ifdef WIN32
namespace platform_stl = winstl;
#elif defined(unix)
namespace platform_stl = unixstl;
# . . .

using platform_stl::performance_counter;
using platform_stl::findfile_sequence;

void measure_interval(. . .)
{
  performance_counter                counter;
  findfile_sequence                  sequence("*.*");
  findfile_sequence::const_iterator  begin = sequence.begin();
  findfile_sequence::const_iterator  end   = sequence.end();

. . .
or with explicit qualification:
// with explicit qualification and namespace aliasing

#ifdef WIN32
namespace platform_stl = winstl;
#elif defined(unix)
namespace platform_stl = unixstl;
# . . .

void measure_interval(. . .)
{
  platform_stl::performance_counter                counter;
  platform_stl::findfile_sequence                  sequence("*.*");
  platform_stl::findfile_sequence::const_iterator  begin = sequence.begin();
  platform_stl::findfile_sequence::const_iterator  end   = sequence.end();

. . .

The technique is very simple, but it is surprising how often it is overlooked.

Notes and References

[1] More Exceptional C++, Herb Sutter, Addison-Wesley 2002.

[2] "Uncaught Exceptions", Bobby Schmidt, C/C++ User's Journal, September 2001.

[3] "Uncaught Exceptions", Bobby Schmidt, C/C++ User's Journal, January 2002.

[4] It should be noted that discriminating against existing—in so far as they are defined by your compiler and/or platform—symbols is less fraught than creating your own. Of course it is possible, though less manageable, to eliminate all the preprocessor logic entirely, by working with include paths.

[5] "Open-Source Flexibility via Namespace Aliasing," Matthew Wilson, C/C++ User's Journal, July 2003.

[6] The C++ Programming Language, 3rd Edition, Bjarne Stroustrup, Addison-Wesley, 1997.

About the Author

Matthew Wilson is a software development consultant for Synesis Software, and creator of the STLSoft libraries. He is author of the forthcoming book Imperfect C++ (to be published this fall by Addison-Wesley, 2004), and is currently working on his next two books, one of which is not about C++. Matthew can be contacted via http://stlsoft.org/.

TOP 5 ARTICLES
No Top Articles.



MICROSITES
FEATURED TOPIC

ADDITIONAL TOPICS

INFO-LINK