[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