[Development] inline namespaces as a versioning tool (was: Re: QList)

Marc Mutz marc.mutz at kdab.com
Thu Mar 30 11:40:53 CEST 2017


On Thursday 30 March 2017 11:31:11 Olivier Goffart wrote:
> On Donnerstag, 30. März 2017 11:08:45 CEST Marc Mutz wrote:
> > On Thursday 30 March 2017 08:41:51 Olivier Goffart wrote:
> > > On Donnerstag, 30. März 2017 08:32:24 CEST Marc Mutz wrote:
> > > > On Thursday 30 March 2017 08:18:52 Olivier Goffart wrote:
> > > > > On Donnerstag, 30. März 2017 07:20:11 CEST Marc Mutz wrote:
> > > > > > On Wednesday 29 March 2017 22:12:30 Thiago Macieira wrote:
> > > > > > > On quarta-feira, 29 de março de 2017 11:11:58 PDT Marc Mutz 
wrote:
> > > > > > > > Keyword: inline namespaces. This is the C++ mechanism for API
> > > > > > > > versioning. It allows to make that totally transparent. Why
> > > > > > > > you find that so odd as to be lacking for words is beyond
> > > > > > > > me.
> > > > > > > 
> > > > > > > Inline namespaces do not solve the binary compatibility
> > > > > > > problem. They should not be used in Qt API for versioning.
> > > > > > > 
> > > > > > > Instead, do what you said before: create a V2 class.
> > > > > > 
> > > > > > Since the two are totally identical, except that inline
> > > > > > namespaces are transparent to the user, please explain what
> > > > > > leads you to this distinction.
> > > > > 
> > > > > Library 1:
> > > > >  inline namespace v1 { class Foo {}; }
> > > > > 
> > > > > Library 2:
> > > > >  LIBRARY2_EXPORT void registerPlugin(Foo*);
> > > > >  
> > > > >     -> symbol gets mangled as "registerPlugin(v1::Foo*)"
> > > > > 
> > > > > Application:
> > > > >   registerPlugin(new Foo);
> > > > >   
> > > > >      -> calls exported symbol "registerPlugin(v1::Foo*)"
> > > > > 
> > > > > When Library 1 puts Foo in the v2 inline namespace,  recompile
> > > > > Library2
> > > > > and
> > > > > the exported symbol becomes "registerPlugin(v2::Foo*)". If
> > > > > Application is not recompiled, it will not work as the old symbol
> > > > > is no longer found.
> > > > 
> > > > Well, of couse. That's like removing the QFoo overload when you add
> > > > QFooV2. Don't do that. You need to keep the v1::Foo definition as
> > > > well as the v1::Foo overload, just as you need to keep the QFoo
> > > > definition and the QFoo overload, when you add v2.
> > > 
> > > What I meant is that Library 1 becomes, in its next version
> > > 
> > >  namespace v1 { class Foo{}; }
> > >  inline namespace v2 { class Foo{}; }
> > > 
> > > It keeps  v1::Foo,  but puts v2::Foo in the inline namespace.
> > > 
> > > If you don't use "inline namespace v2", that means users needs to
> > > explicitly use v2::Foo to use the new features. So it is no longer
> > > "transparent to the user"
> > 
> > Ok, no.
> > 
> > library V1:
> >     inline // this inline is optional for V1 - users with compilers
> >     without
> >     
> >            //  support for them need to write v1:: explicitly, or it can
> >            be // reasonably emulated with a ...
> >     
> >     namespace v1 { class Foo{ int i, }; }
> >     
> >            // ... using v1::Foo, here
> >     
> >     LIB_EXPORT void useFoo(Foo);  // actually v1::Foo
> > 
> > user V1:
> >     useFoo(Foo{});  // actually v1::Foo
> > 
> > library V2:
> >     namespace v1 { class Foo{ int i; } } // from V1 of library
> >     inline
> >     namespace v2 { class Foo{ v1::Foo f; double d; } // adds a double
> > 
> > member,
> > 
> >                                                     // reuses v1::Foo
> > 
> > LIB_EXPORT void useFoo(v1::Foo); // from V1 of library
> > LIB_EXPORT void useFoo(Foo);     // actually v2::Foo
> > 
> > user V2 @ library V2:
> >     useFoo(Foo{}); // actually v2::Foo
> > 
> > user V1 @ library V2:
> >     (compiled and continuing to run as) useFoo(v1::Foo{});
> > 
> > -> totally transparent, BC and SC
> > 
> > Where's my mistake?
> 
> That works fine as long as there is only one library involved.
> It stops working once the library is used in the ABI of another library.
> 
> Example: Qt used by KDE frameworks used by applications. Or stdlib used in
> the ABI of Qt.
> 
> 
> 
> Imaging we have a ExLibrary that links against Library:
> 
> ExLibrary:
>  EXLIB_EXPORT void exUseFoo(Foo);
>  EXLIB_EXPORT Foo exGetDefaultFoo();
> 
> ExLibrary @ Library V1
>  -> exports "exUseFoo(v1::Foo)"
>  -> exports "exGetDefaultFoo()" returning an object v1::Foo
> 
> 
> ExLibrary @ Library V2
>  -> exports only "exUseFoo(v2::Foo)"
>  -> still exports "exGetDefaultFoo()", but it returns a v2::Foo now, which
> does not have the same layout
> 
> The problem is: as ExLibrary gets recompiled against the new version of
> Library, it no longer exports the old symbols.

Ok, not 100% transparent in all cases, then. But a symbol comparison like we 
do before a release will highlight this.

Anyway, apart from transparency: how is that different from QFoo followed up 
by QFooV2?

Thanks,
Marc

-- 
Marc Mutz <marc.mutz at kdab.com> | Senior Software Engineer
KDAB (Deutschland) GmbH & Co.KG, a KDAB Group Company
Tel: +49-30-521325470
KDAB - The Qt, C++ and OpenGL Experts



More information about the Development mailing list