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

Olivier Goffart olivier at woboq.com
Thu Mar 30 11:31:11 CEST 2017


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.


-- 
Olivier

Woboq - Qt services and support - https://woboq.com - https://code.woboq.org




More information about the Development mailing list