[Development] Qt 6: inline namespace Qt

Mutz, Marc marc at kdab.com
Fri Sep 6 11:26:43 CEST 2019


Hi,

I would like to propose to make the existing Qt namespace inline and 
move all of Qt's declarations into it.

== TL;DR: ==

Qt can already, optionally, be configured into a user-specified 
namespace (QT_BEGIN_NAMESPACE/QT_END_NAMESPACE, -qtnamespace), and this 
is one of the build configurations in the CI, so we're reasonably sure 
it works. The change would be very limited (via existing macros). Only 
pre-existing declarations of "namespace Qt" would have to be touched. 
The change is SC, and makes namespaced and non-namespaced builds behave 
the same.


== Rationale ==

As we see with the introduction of Qt::endl, a SiC change, we have a 
problem in that we have existing Qt API that traditionally (dare I say 
"for decades") doesn't have a Q/q prefix. Adding Qt:: in front now is a 
massive SiC change. Making the Qt namespace inline allows users to 
continue to write << endl; while we still have the symbol moved out of 
the global namespace.

Furthermore, the global namespace is special in that ADR does "not work 
in it"[1]; [1] can be summarized as "C++ just works better when all 
types are in some namespace". This means that we have very subtle 
differences in name lookup, depending on whether Qt is compiled with 
-qtnamespace or without. I remember having hit these multiple times in 
the past, but can't remember details anymore (and one or the other might 
have had to do more with two-phase name lookup in templates, and not 
with ADR).

[1] 
https://groups.google.com/forum/#!msg/comp.lang.c++.moderated/1Qz71aFnXlI/Gd71gwRaWssJ

The language has also started stipulating in a few places that certain 
functions are only found via ADR, not by ordinary name lookup (the 
begin() and end() functions called by ranged-based loop for non-array 
types that don't have a .begin()/.end() come to mind). There seems to be 
some confusion[2] over whether that means that functions in the global 
namespace would be found at all under such circumstances (I guess Ville 
could confirm or deny), and vice versa: when functions are defined as 
friends in the body of types (in which case they're only found via ADL 
and not via ordinary name lookup) in the global namespace, do they exist 
at all? But we can do very well without such dipping into C++'s dark 
corners: if we are always in a namespace, ADL always works.

[2] 
https://stackoverflow.com/questions/25133383/does-adl-work-for-the-global-namespace

Thus, I'd like to propose to move all of Qt into an inline namespace Qt. 
Any user namespace would be wrapping it:

   inline namespace Qt {
       class QString;
   }

without `-qtnamespace` and

   namespace TestNamespace {
   inline namespace Qt {
       class QString;
   }
   }

with `-qtnamespace TestNamespace`.

Because the namespace is inline, existing code will just have to be 
recompiled to pick it up. In particular, no `using namespace Qt` is 
needed anywhere to still use QString etc unqualified, yet, the 
executable would refer to Qt::QString everywhere. Even 
Q_DECLARE_TYPEINFO would continue to work unchanged, since you don't 
need to open an inline namespace to specialise templates from it.

It's a BiC change, though, so it's for Qt 6.0, if ever.


== Design Decisions ==

=== inline Qt::Qt3D or inline Qt3D ? ===

Some Qt modules have started using a (non-inline) namespace, often 
derived from the module or library name, since Qt 4 (QtPatternist, 
QtConcurrent, Qt3D, ...). A legitimate design would leave the Qt 
namespace alone, and put each library Lib into an inline namespace QtLib 
instead. This would solve the same problems, and could be used to unify 
the different libraries' choices of handling naming. The reason that 
it's not proposed here is that it's a much grander scheme than just 
wrapping everything into `inline namespace Qt` - all the Qt modules are 
already known to work with the user namespace feature and this proposal 
simply suggests to append `inline namespace Qt {` to QT_BEGIN_NAMESPACE 
so that this macro always expands to at least one namespace begin. 
Giving each module or library its own inline namespace would be much 
more work.


Flame away :)

Thanks,
Marc



More information about the Development mailing list