Thread overview
Fragile virtual functions
Mar 08, 2008
Michel Fortin
Mar 08, 2008
Janice Caron
Mar 08, 2008
Michel Fortin
Mar 08, 2008
Craig Black
Mar 09, 2008
Michel Fortin
Mar 09, 2008
Janice Caron
March 08, 2008
If I understand well the virtual function dispatching mechanism, if you have a library with some class, such class having virtual functions, adding a new virtual function to that class will make the ABI incompatible with already-compiled subclasses having more virtual functions, and if you don't add your function at the end of a class definition, with already compiled code calling virtual functions for your class. Am I the only one seeing that as a weakness for object-oriented libraries?

I've seen a recommendation somewhere (for C++) suggesting that virtual functions should be made protected and that public functions should be created for calling the protected virtual functions. This doesn't protect the subclasser from this problem, but it protects the caller of a virtual function which is liberated from having to perform the virtual dispatching by itself (and thus from having knowleadge of the virtual table layout).

I was wondering if the D compiler couldn't do that by itself: create a "trampoline" function for every virtual call which would do the dispatching for you by loading the actual function address and branching directly to it (without really adding a function on the stack). Then a client of your library would be shielded from you adding more functions to your class.

Thoughts? I'm particularly wondering about the speed penalty it could incur.

-- 
Michel Fortin
michel.fortin@michelf.com
http://michelf.com/

March 08, 2008
If a class changes (or a struct, or an enum, or a typedef, or a template, or ... /anything/ ...) then anything which uses it must be recompiled. That's just how it works.

Most people have a build system to automate this. (make, dsss, whatever). It's not hard. Basically you just rebuild all the dependencies.
March 08, 2008
On 2008-03-08 07:59:38 -0500, "Janice Caron" <caron800@googlemail.com> said:

> If a class changes (or a struct, or an enum, or a typedef, or a
> template, or ... /anything/ ...) then anything which uses it must be
> recompiled. That's just how it works.
> 
> Most people have a build system to automate this. (make, dsss,
> whatever). It's not hard. Basically you just rebuild all the
> dependencies.

I know you can just recompile everything and it'll work, but I'm wondering about how to provide a stable API in a dynamic library which can stay compatible even when a client application isn't recompiled.

You can add new functions, new types, etc. to a module and keep the binary compatibility, but adding, or just reordering, member functions of a class break that compatiblity and I wondered if this could be mitigated with the way I suggested it.

As a counter-example, take an Objective-C API: you can add member functions as much as you like, even reorder them in the source code, and you'll keep binary compatibility in a library. It's no wonder why Apple prefers to not expose C++ API for their operating system. They use C++ internally for many things (you know when you get a stack trace), but they don't expose that.

-- 
Michel Fortin
michel.fortin@michelf.com
http://michelf.com/

March 08, 2008
"Michel Fortin" <michel.fortin@michelf.com> wrote in message news:fqtuqt$nfd$1@digitalmars.com...
> If I understand well the virtual function dispatching mechanism, if you have a library with some class, such class having virtual functions, adding a new virtual function to that class will make the ABI incompatible with already-compiled subclasses having more virtual functions, and if you don't add your function at the end of a class definition, with already compiled code calling virtual functions for your class. Am I the only one seeing that as a weakness for object-oriented libraries?
>
> I've seen a recommendation somewhere (for C++) suggesting that virtual functions should be made protected and that public functions should be created for calling the protected virtual functions. This doesn't protect the subclasser from this problem, but it protects the caller of a virtual function which is liberated from having to perform the virtual dispatching by itself (and thus from having knowleadge of the virtual table layout).
>
> I was wondering if the D compiler couldn't do that by itself: create a "trampoline" function for every virtual call which would do the dispatching for you by loading the actual function address and branching directly to it (without really adding a function on the stack). Then a client of your library would be shielded from you adding more functions to your class.
>
> Thoughts? I'm particularly wondering about the speed penalty it could incur.

I am the primary author of an API that is used by other programmers.  It uses plugin libraries.  Adding new virtual functions does change the ABI and it's very annoying.  Developers that use this API will usually complain if there is an ABI change, because it means that everyone's plugins have to be recompiled for compatibility.  This somewhat cripples development when ABI compatibility is required.

So I concur with your observation that this is a problem.  However, I would consider your suggestion to be an incomplete solution.  Because, as you say, it doesn't solve the problem for subclasses.  Does anyone have an idea that would be a full solution?  Of course, we are not talking about modifying or removing existing virtual functions.  Just adding them.

-Craig 

March 09, 2008
On 2008-03-08 17:48:14 -0500, "Craig Black" <craigblack2@cox.net> said:

> I am the primary author of an API that is used by other programmers.  It uses plugin libraries.  Adding new virtual functions does change the ABI and it's very annoying.  Developers that use this API will usually complain if there is an ABI change, because it means that everyone's plugins have to be recompiled for compatibility.  This somewhat cripples development when ABI compatibility is required.
> 
> So I concur with your observation that this is a problem.  However, I would consider your suggestion to be an incomplete solution.  Because, as you say, it doesn't solve the problem for subclasses.  Does anyone have an idea that would be a full solution?  Of course, we are not talking about modifying or removing existing virtual functions.  Just adding them.

I also consider it an incomplete solution, but it's still better than nothing.

I think solving the problem for subclasses would require the virtual table to be dynamically built while loading the library, and the virtual table offsets for the trampoline functions I suggested in my last post would have to be set accordingly at the same time.

-- 
Michel Fortin
michel.fortin@michelf.com
http://michelf.com/

March 09, 2008
On 08/03/2008, Craig Black <craigblack2@cox.net> wrote:
>  Does anyone have an idea that
>  would be a full solution?

Probably not a full solution, but have you considered COM? Or better still, XPCOM? http://www-128.ibm.com/developerworks/webservices/library/co-xpcom.html