#046 – How to use inline namespaces to version source code

Shipping a new version of a function without breaking existing callers is a recurring problem in library design.

Renaming the function forces an update to every caller; leaving it alone means living with the old behaviour forever. C++ offers a quiet, elegant tool for this exact case: the inline namespace.

The mechanism

If a namespace is labelled as inline, if a function call is made to it and the identifier is present in another namespace, the compiler will prioritise the inline namespace.

#include <iostream>
#include <iomanip>

namespace physics
{
    namespace v1 
    {
        constexpr double boltzmann { 1.38064852e-23 };
    }

    inline namespace v2 
    {
        constexpr double boltzmann { 1.380649e-23 }; // Modern version
    }
}

int main() 
{
    std::cout << std::scientific << std::setprecision(8);

    // 1. Default access (Points to v2 because it is inline)
    std::cout << "Default k: " << physics::boltzmann << "\\n\\n";

    // 2. Explicit legacy access
    std::cout << "Legacy k:  " << physics::v1::boltzmann << "\\n\\n";
}

We can safely refactor a method without breaking the existing function calls.

Calling physics::boltzmann will select the newest version, in this case, v2::boltzmann

Also, if you want to change which function is called, you remove the inline keyword. This is superior to scouring the source code and changing each function call.

The old version is still accessible via physics::v1::

Expanding the library

Suppose a new version is released. The new functionality can be wrapped in a new v3 namespace.

namespace physics
{
    namespace v1 { /* ... */ }
    namespace v2 { /* ... */ }      // Revoke the inline label

    inline namespace v3 { /* ... */ } // new version
}

Every caller of boltzmann if unscoped, resolves to v3 without a single edit to the caller. Callers that explicitly named physics::v2::boltzmann continue to compile and behave exactly as before.

A real-world example

If you need anymore proof of using inline namespaces for API versioning, take a look at the Standard Library

In libc++, types live inside std::__1::, an inline namespace nested under std. Most users never see the __1:: and treat the types as plain std:: members. This is exactly the point — the inline namespace is invisible until you need it.

In Summary

Using inline namespaces allows to identical functions to live in harmony.

This allows a library to evolve without breaking existing code.

The workflow:

ActionResult
EncapsulatePlace different versions of the API into distinct nested namespaces (e.g., v1, v2).
PromoteLabel the current “production” namespace as inline to make its members visible in the parent scope.
PreserveKeep legacy versions in standard (non-inline) namespaces so they remain accessible via explicit scoping.
EvolveTo release a new version, simply move the inline keyword to the newest namespace.

Unscoped function calls automatically link to the inline version whilst simultaneously maintaining legacy code. Two birds. One stone.