Inline Namespaces

One of the neat, new language features of C++0x that is targeted firmly at framework designers is the ability to declare “inline” namespaces. While the name may seem a bit strange at first, the concept is quite intuitive. It allows a framework designer to version the APIs within their namespace.

Let’s get concrete! Suppose you have a framework that implements networking functionality. You’ve got a few classes for TCP and UDP support, and they’re placed within a Networking namespace. Like so:

namespace Networking {
	class TCPSocket;
	class UDPSocket;
}

This works great, but what if you decide you want to build a better socket? Previously, you have several choices of ways to deal with this problem. First, you could simply replace TCPSocket with your new class. The downside to this approach was that you have to be absolutely certain the behavior was 100% identical, or else old code might break. Or, you could add a NewTCPSocket class, and have new code start using it. This, of course, is quite ugly. Or you could turn TCPSocket into a bridge, and have different implementations internally, but that would require changing existing code to use the factory. And there are other ways you could solve this as well — C++ is a versatile language!

But the solution I want to explore today is using namespaces to do versioning for you. You could decide to wrap the TCPSocket in a namespace, and wrap the new TCPSocket in its own namespace:

namespace Networking {
	namespace V1 {
		class TCPSocket;
	}
	
	namespace V2 {
		class TCPSocket;
	}

	class UDPSocket;
}

The benefit of this approach is that you can reuse the name TCPSocket because both reside in separate namespaces. But the downside is that you would break existing code, since it doesn’t use the V1 or V2 namespaces.

Now in C++0x, we can alleviate that downside by using an “inline namespace.” This allows you to pick a “default” namespace that gets imported in along with the outer namespace. For instance, with our example:

namespace Networking {
	namespace V1 {
		class TCPSocket;
	}
	
	inline namespace V2 {
		class TCPSocket;
	}

	class UDPSocket;
}

By making V2 an inline namespace, it means that whenever anyone uses the Networking namespace, all of the names from V2 are also automatically imported. Effectively, when you use the inline keyword with the namespace, it’s like having the compiler automatically put a using statement in for the inlined namespace.

An example might make this more clear, from our previous code:

Networking::TCPSocket *t;		// Networking::V2::TCPSocket, because of the inline namespace
Networking::V1::TCPSocket *t2;		// Networking::V1::TCPSocket
Networking::V2::TCPSocket *t3;		// Networking::V2::TCPSocket

using namespace Networking;
TCPSocket *t4;				// Networking::V2::TCPSocket, because of the inline namespace
V1::TCPSocket *t5;			// Networking::V1::TCPSocket
V2::TCPSocket *t6;			// Networking::V2::TCPSocket

Inline namespaces allow the framework implementer the control to determine what namespaces are automatically considered “the default.” So if you want everyone to automatically get the newest version of the TCPSocket class, you can inline namespace V2. Or if you want to go the safe route and not change any existing code, you can inline namespace V1.

You can also do this for any number of namespaces. So, for instance, if you come up with V3 of your networking code that has a new UDPSocket, you could do this as well:

namespace Networking {
	namespace V1 {
		class TCPSocket;
		class UDPSocket;
	}
	
	inline namespace V2 {
		class TCPSocket;
	}

	inline namespace V3 {
		class UDPSocket;
	}	
}

This means that users will get the latest UDPSocket class, but can always go back to V1::UDPSocket if they wish.

Another useful thing to keep in mind is that the inline keyword can be switched “on and off” using the preprocessor. So, for instance, if you want to include some extra debugging functionality, or an optimized version of your framework, you can do so. For instance, let’s say we wrote a raw socket implementation of the UDPSocket class, we could do:

namespace Networking {
	namespace V1 {
		class TCPSocket;
		class UDPSocket;
	}
	
	inline namespace V2 {
		class TCPSocket;
	}

#ifndef USE_RAW_SOCKETS
	inline
#endif
	namespace V3 {
		class UDPSocket;
	}
	
#ifdef USE_RAW_SOCKETS
	inline
#endif
	namespace RawUDPSockets {
		class UDPSocket;
	}	
}

This would allow you to pick whether V3 is the default, or RawUDPSockets is the default, depending on the USE_RAW_SOCKETS macro.

Even if you’re not a framework designer, inline namespaces are a powerful tool in your arsenal as a C++ programmer, because they allow you to refactor your code with less worry about breakage. You can use the inline namespace to pick the default behavior, but still retain the original code to use as fallbacks while performing your refactoring.

tl;dr: inline namespaces help you version your frameworks. Anything inlined can be used without the namespace qualifier.

This entry was posted in C/C++, Framework Design and tagged , . Bookmark the permalink.

4 Responses to Inline Namespaces

  1. werelord says:

    Per your example, you can inline multiple namespaces; but both inline namespaces had different classes.. What if the same class names were declared within both inlined namespaces; compiler error??


    namespace Networking {
    namespace V1 {
    class TCPSocket;
    class UDPSocket;
    }

    inline namespace V2 {
    class TCPSocket;
    }

    inline namespace V3 {
    class TCPSocket; // error?? or which one is defaulted if not explicitly declared?
    }
    }
    </code

  2. Aaron Ballman says:

    Both class names would be imported into the containing namespace, which would cause a conflict and the compiler would report an error. But this should not come as too much of a surprise — it’s no different (conceptually) from defining multiple classes in the global namespace with the same name.

  3. minime says:

    I don’t see any difference to namespace V1{ }; using namespace V1; here

  4. Aaron Ballman says:

    @minime: I’m not certain I understand what “here” means. Do you have a specific example in mind?

Leave a Reply

Your email address will not be published.