6

It is good programming style to include all necessary dependencies in a header that references them. Often this includes declarations that are placed in the STD & global namespaces (like cstdio). However, this creates problems when a second programmer wants to wrap such an include file in a new namespace to encapsulate the first one.

With this scenario in mind, is there a way to force declarations into the global name space? As a conceptual example (this won't actually compile):

foo.h --> original definition
// force global namespace, this is redundant when foo is in the global space
//   but could be important if foo included into another namespace.
namespace :: { 
  #include <cstdio>
}
namespace foo {
  FILE *somefile;
}


bar.h --> New file, by a new programmer, encapsulating foo.
namespace bar {
  # include "foo.h"
  FILE *somefile;  // bar:somefile, as opposed to bar::foo::somefile
}

Without the putative namespace ::{} we end up with declarations like foo::FILE, and foo::printf(), when we just want ::FILE and ::printf().

Popular libraries like boost resolve this by defining an explicit hierarchy. That would require that foo know it will be part of bar, and place global namespace includes outside of the local namespace definition.

However, good extensibility requires that we be able to use foo directly, OR wrap foo in a new namespace, without having to change foo or its includes.

Does anyone know how to accomplish this?

9

Including a header into a namespace is prone to break various assumptions, and should not be done. Problems that come to mind are:

  • It breaks include guards. If a header can only be included once, and you include it into the wrong namespace, then other code can't include it into the correct namespace within the same compilation unit. Or the other way round: if it was already included by a library, you can't re-include it somewhere else. E.g.:

    someLib/A.h

    #ifndef SOMELIB_A_H_
    #define SOMELIB_A_H_
    // assume this will be included into namespace someLib
    class A {};
    #endif
    

    someLib/B.h

    #ifndef SOMELIB_B_H_
    #define SOMELIB_B_H_
    namespace someLib
    {
        # include "A.h"
        int b(const A& a) { return 42; }
    }
    #endif
    

    usercode.cpp

    // defines someLib::b and somelib::A
    #include <somelib/B.h>
    // include A into global namespace
    // – won't work because someLib/A.h was already included
    #include <somelib/A.h>
    #include <iostream>
    int main()
    {
        std::cout << someLib::b(A()) << '\n';
        return 0;
    }
    

    This will fail because #include <someLib/A.h> is a no-op in the main program, and does not include anything. Therefore, A is undefined in the main program. If the files were included the other way round, it would work since the someLib::b declaration can also see symbols in the global scope. However, the order of includes should not matter in a well-designed library!

  • You won't be able to link. Most header files have an associated .cpp file that includes private implementation details. If you include a header into a different namespace, then it can't link with the implementation.

  • It breaks macros. If a library-provided macro calls back into a library, it will always have to use the fully namespace-qualified name, since we do not know from which namespace it will be used. If you manage to include a symbol foo::bar::BazException as qux::BazException, then a perfectly reasonable macro such as

    #define FOO_BAR_BAZEXCEPTION(expr) foo::bar::BazException(expr, __FILE__, __LINE__)
    

    will stop working.

  • It breaks argument-dependent lookup, which only works if the function and its arguments share a namespace.

If including a file into a namespace is such a horrible idea and will break more stuff than it fixes, what are the alternatives?

First of all, namespaces are good. They help us to give structure to the overall architecture, even if they are very open. We use namespaces not only because they impose a convenient hierarchy that avoids name clashes, but also because some features such as argument-depedent lookup depend on it. The only reason why the standard library puts some symbols into the global scope is compatibility with C. Even then, you can access the symbols through the std:: namespace, which should be preferred.

Some people feel that namespaces might become inconveniently long. This is no problem because we can define shorter aliases in the scope where they are needed with using foo::bar::Baz. This is also the solution when putting symbols into the global scope: an alias does not hide the original, fully-qualified name, so all the problems mentioned above do not apply. The using directive has lots of uses, and can alias namespace, typenames, and values such as variables or member functions.

When you include a file, always assume that it is properly namespaced. Therefore, include it in global scope before you open any namespace of your own. Even if the headers are from your own project, make sure they declare their own namespaces. This also means that the structure of namespaces is fairly difficult to change once it is fixed. But that is good – any change to your public interface (which includes the namespace structure) would also require all dependent code to change. I do not see how “good extensibility” would require us to give up this structure.

  • This is a great response, thank you. The short answer seems to be that namespace hierarchies were designed to be statically defined at design time, and not used in extensive design. That is, not available to wrapped in other namespaces post-design. I believe this limitation is not necessary, but it clarifies my immediate inquiry. I’ve added a bit to the question to demonstrate how namespaces could be made more extensible. However, using namespaces that way, even if possible, seems antithetical to their current design philosophy. I’ll avoid it. Thanks again. – bgulko Oct 1 '15 at 19:14
  • Not sure I agree that including a header into a namespace is always a bad idea. softwareengineering.stackexchange.com/questions/335240/… – AlwaysLearning Nov 3 '16 at 6:47
  • @AlwaysLearning But that question itself shows what is IMO a horrible practice. – Sebastian Redl Nov 4 '16 at 9:48
  • 1
    Good answer, just some notes on terminology: a using directive doesn't alias anything, it just brings an entire namespace into the current scope for lookup (it's the using namespace x; form). A using declaration brings a single declaration into the current namespace (the using x::y; form). An alias declaration renames a single type (the using x = y; form), or introduces a template of aliases. And a namespace alias renames a single namespace (the namespace x = y; form). – Sebastian Redl Nov 4 '16 at 9:50
2

Simple- don't do that shit.

Including a header into a namespace is a dumb thing to do and should not be done. If you're not happy with the namespacing of a header, then either complain to the author or fork the header. Including the header into a namespace is completely ineffective and pointless.

  • I appreciate the feedback, but I don't see your point. I'm looking for a way to create C++ definition sets that can be used directly, or encapsulated into namespaces. I'm afraid "don't do that" without explanation doesn't really help. Without care, poor header design can cause a variety of problems, regardless of weather or not they are included in a namespace (i.e. using namespace std). With care they represent definitions that would do just fine in namespaces. – bgulko Sep 29 '15 at 20:57
  • 6
    -1 for cursing and not explaining why it shouldn't be done. – Matthew James Briggs Sep 30 '15 at 3:06
  • Not sure I agree that including a header into a namespace is always a bad idea. softwareengineering.stackexchange.com/questions/335240/… – AlwaysLearning Nov 3 '16 at 6:47
2

The short answer seems to be that namespace hierarchies were designed to be statically defined at design time, and not used in extensive design. That is, not available to wrapped in other namespaces post-design. Thus, they are more a tool for preventing one's own code from polluting the global space, rather than for containing namespace pollution from other people's code. I believe this limitation is not necessary, but it clarifies my immediate inquiry.

Some additional work yielded a partial solution, but the short answer is that namespaces were not designed to be nested after design. Using them this way, even if possible, is counter to the design intent, and therefore a bad idea. That said, here is a method of achieving it.

I believe most of the issues with linkage could be resolved by two practices:

  1. Making sure that non-inline includes were homed in the global namespace.
  2. Only extending inline / header based namespaces.

The first could be performed now by creating an name_ext.h file for each namespace and including it at global scope. A derived namespace would have its own derived_ext.h that include all dependent name_ext.h, thus employing multiple-include-barriers to insure that global includes were homed in the global namespace. This would preserve binary library linkage. A namespace :: {} extension to home definitions in the global namespace from inside an existing namespace block, would fix this more elegantly.

The second point deals with compile time linkage of .cpp files. I’ve tested this and it works.

The only remaining issue is that of multiply homed classes. Without some substantial preprocessor support for dynamic include-barriers, it would render it impossible to have multi-homed namespaces, which is ultimately a real problem for design orthogonality.

However this would still be limited to namespaces completely contained in include files.

In any case using namespaces this way, even if possible, seems antithetical to current design philosophy.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.