Home > Software design >  Add a new namespace in API backwards compatible way
Add a new namespace in API backwards compatible way

Time:11-23

There is a library with this public class.

namespace lib {
class Class {};
}

I want to refactor it and add one more namespace.

namespace lib::sublib {
class Class {};
}

I want to make it API backwards compatible so existing library clients can compile with the new library version without changing their code. I tried adding an alias.

namespace lib {
using Class [[deprecated]] = sublib::Class;
}

This works in most cases, except if library clients forward declare lib::Class.

namespace lib {
class Class;
}

In this case there is an error about conflicting declarations.

<source>: error: conflicting declaration 'using Class = class lib::sublib::Class'
   10 |     using Class = sublib::Class;
      |           ^~~~~
<source>: note: previous declaration as 'class lib::Class'
    2 |     class Class;
      |           ^~~~~

Is there a way to add a new namespace and do not break the existing code? This question is only about API. ABI backwards compatibility is not needed.

CodePudding user response:

Namespaces (inline or not) and class aliases aren't symlinks.

There is no way to move the actual definition of a class into a different namespace while simultaneously making all uses of that class declaration in the prior namespace valid. You can make most uses of the class name valid, but not those involving class declarations.

A class lives in exactly one place, and all declarations of that class must agree on where it lives. There may be other locations through when you can access the name, but declarations have to pick the actual location of it.

So you either cannot move this class declaration or you must accept that users who forward declare the class will get breakages when you move it.

CodePudding user response:

There is a good rule to never put "using namespace" in header files. But for transition periods to a new namespace it can really help. If you do it like this then you can start adding the compiler option macro USE_MY_API_NAMESPACE one client project at a time. And then start adding new_namespace:: to the client code where needed.

// header file
#pragma once 

// your new namespace
namespace new_namespace
{
    // your current api
    void api_func();
}

// even though using namespace isn't recommended
// during transition it won't make things worse
// since the existing API is in the global namespace anyway
// just don't forget to add removing these lines
// as technical debt to your project bugtracking database.

#ifndef USE_MY_API_NAMESPACE
using namespace new_namespace;
#endif 

// end of header file
  • Related