www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Fragile virtual functions

reply Michel Fortin <michel.fortin michelf.com> writes:
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/
Mar 08 2008
next sibling parent reply "Janice Caron" <caron800 googlemail.com> writes:
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.
Mar 08 2008
parent Michel Fortin <michel.fortin michelf.com> writes:
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/
Mar 08 2008
prev sibling parent reply "Craig Black" <craigblack2 cox.net> writes:
"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
Mar 08 2008
next sibling parent Michel Fortin <michel.fortin michelf.com> writes:
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/
Mar 08 2008
prev sibling parent "Janice Caron" <caron800 googlemail.com> writes:
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
Mar 08 2008