Document number: J16/06-0083 = WG21 N2013
Date: 2006-04-19
Author: Benjamin Kosnik <bkoz@redhat.com>
Evolution Working Group, Modules and Linkage

Versioning with Namespaces



Introduction.

Elegant transitions between components of the C++ standard as it evolves are possible without too much work. This paper will outline an approach using an extension to namespace using directives, and a careful arrangement of nested namespaces within namespace std. A careful arrangement is composed by partitioning namespace std into a collection of nested namespaces named after a specific revision of the standard, and then placing specific types within one of the unique nested namespace partitions. The end result is a flexible solution with options for both binary and source compatibility.

This was initially presented to the modules working group during the April, 2006 meeting in Berlin. Ideas for alternate syntax are inspired by that discussion.

Language additions.

The usual language rules with respect to namespaces are not sufficient to allow the designs described below. A short study of the relevant issues can be found in Herb Sutter's paper N1344=02-0002.

Therefore, a capability similar to the extension designated "namespace association" is assumed, and is described by N1526=03-0109. In addition, a further restriction on this extension is imposed, making it only applicable to nested namespaces.

To recap, this extension does the following:

(1) At any time, in a given translation unit, one wants to pretend that a set of names that are defined in a namespace N, are also members of a namespace M, for all purpose but linkage (i.e. name mangling).

(2) Furthermore, one wants to retain usual lookup rules, in particular argument dependent lookup, member definition rules, etc.

In addition, the syntax is slightly changed for the purpose of clarity. Instead of logical operators, the keyword "case" is re-used in combination with the usual namespace directive syntax to identify an explicit namespace association.

namespace std 
{
  namespace _1998
  {
    template<typename T>
      struct A { };
  }
  using namespace case _1998; // associate _1998 with std

  template<>
    struct A<int> { };  // ok to specialize
}

std::A<float> obj; // ok, fully qualified as std::_1998::A

Also, the predefined macro __STDCXX_VERSION__, similar to __STDC_VERSION__ from ISO C99, is used to distinguish between the original C++ standard (ISO 14482, referred to as C++98) and a future standard (referred to as C++0x). This is only one possible mechanism: the exact mechanism can be left as an implementation detail.

Library implementation for source compatibility.

The following arrangement provides seamless source compatibility, but changes the actual definitions of elements from C++98 and C++0x to nest within namespace std as in the following (incomplete) example:

namespace std
{
  namespace _1998
  {
    template<typename _Tp>
      class allocator { };

    template<typename _CharT, typename _Traits, typename _Alloc>
      class basic_string { };
  } 

  namespace _2008
  {
    template<typename _Tp>
      class reference_wrapper { };
  }

#if __STDCXX_VERSION__ >= 199801L
  using namespace case _1998;
#endif

#if __STDCXX_VERSION__ >= 200801L
  using namespace case _2008;
#endif
}

This arrangement presumes that types stay compatible, and are not substantially revised in subsequent versions of the standard. For instance, it's assumed that std::basic_string would refer to std::_1998::basic_string only, and similarly for std::_2008::reference_wrapper and the like.

If types don't stay compatible between different versions of the standard, an approach like the above can still be used, but more work will need to be done. One approach would be to further partition the nested namespace into compatible and incompatible partitions, and then only associate the compatible namespace.

Although this would break binary compatibility, this type of design is preferred. The added flexibility of allowing incompatible designs, and the consistent partitioning and placement of all types would allow older (flawed) elements to be gradually deprecated, without throwing out all the other elements from that version of the standard. Throw out the dirty bathwater, but keep the baby.

Library implementation for source and binary compatibility.

The following arrangement provides seamless source and binary compatibility.

namespace std
{
  template<typename _Tp>
    class allocator { };
  
  template<typename _CharT, typename _Traits, typename _Alloc>
    class basic_string { };

  namespace _2008
  {
    template<typename _Tp>
      class reference_wrapper { };
  }

#if __STDCXX_VERSION__ >= 200801L
  using namespace case _2008;
#endif
}

This arrangement allows mangling that is equivalent to that specified as part of C++98, and presumes that C++0x does not make changes in C++98 types. If incompatible changes are desired in C++0x, then the previous design can be used.

Implementation notes.

For the last two years or more, both EDG and GNU compilers implement the language extension for namespace association, first presented in Technical Report N1526=03-0109. The syntax used is based on GNU attribute syntax, and looks like:

using namespace _1998 __attribute__ ((strong));

instead of:

using namespace case _1998;

This extension has evolved as usage discovered problems. In particular, this extension has changed to only be applicable to nested namespaces.

In addition, the GNU C++ library (libstdc++) has been modified to implement versioning much like the designs discussed, and is currently being tested in experimental linux distributions. Previous to the modification to support versioning, the language extension was also used to implement an extended debug version of the library, with checked iterators and other "safe" STL concepts.

References.

Benjamin Kosnik, Proposal to add namespace references to C++, Technical Report N1526=03-0109, September 18, 2002.

Jason Merrill, 6.8 Namespace Association, GCC Manual. http://gcc.gnu.org/onlinedocs/gcc/Namespace-Association.html#Namespace-Association

Herb Sutter, Namespaces and Library Versioning, Technical Report N1344=02-0002, March 1, 2002.