www.digitalmars.com         C & C++   DMDScript  

D - Virtual methods and class libraries

reply Mike Hearn <mike navi.cx> writes:
Hi,

The D spec says:

"All non-static non-private member functions are virtual. This may sound
inefficient, but since the D compiler knows all of the class hierarchy
when generating code, all functions that are not overridden can be
optimized to be non-virtual."

... but I don't understand how this works when you wish to place objects
into shared libraries. In this case, it might be the case that another
library subclasses the class and therefore the compiler cannot know the
entire class hierarchy.

How is this supposed to work? I know D has no stable ABI, but this could
be a serious problem for people wishing to split programs into multiple
DSOS/DLLS.

If this situation simply is not dealt with currently, a virtual keyword
that forces a method to have a vtable entry may be a useful addition to
the language.

thanks -mike
Apr 19 2004
parent reply "Walter" <walter digitalmars.com> writes:
"Mike Hearn" <mike navi.cx> wrote in message
news:pan.2004.04.19.13.51.27.807711 navi.cx...
 Hi,

 The D spec says:

 "All non-static non-private member functions are virtual. This may sound
 inefficient, but since the D compiler knows all of the class hierarchy
 when generating code, all functions that are not overridden can be
 optimized to be non-virtual."

 ... but I don't understand how this works when you wish to place objects
 into shared libraries. In this case, it might be the case that another
 library subclasses the class and therefore the compiler cannot know the
 entire class hierarchy.

You're right. For those cases, a virtual call will be made. And, even if a non-virtual call can be made, the compiler still puts it in the vtbl[].
Apr 19 2004
parent reply Alexander Larsson <alexl redhat.com> writes:
On Mon, 19 Apr 2004 16:51:50 -0700, Walter wrote:

 
 "Mike Hearn" <mike navi.cx> wrote in message
 news:pan.2004.04.19.13.51.27.807711 navi.cx...
 Hi,

 The D spec says:

 "All non-static non-private member functions are virtual. This may sound
 inefficient, but since the D compiler knows all of the class hierarchy
 when generating code, all functions that are not overridden can be
 optimized to be non-virtual."

 ... but I don't understand how this works when you wish to place objects
 into shared libraries. In this case, it might be the case that another
 library subclasses the class and therefore the compiler cannot know the
 entire class hierarchy.

You're right. For those cases, a virtual call will be made. And, even if a non-virtual call can be made, the compiler still puts it in the vtbl[].

I still don't get it. The typical use case here would be writing a shared library for e.g. a gui, where the app using the library typically derive from classes in the library. Now, when building the library, how does the compiler know that it has to make virtual calls, even though no class in the library overrides the method, because some app code might derive from the class and override the method?
Apr 20 2004
parent reply Andy Friesen <andy ikagames.com> writes:
Alexander Larsson wrote:
 I still don't get it. The typical use case here would be writing a shared
 library for e.g. a gui, where the app using the library typically derive
 from classes in the library. Now, when building the library, how does the
 compiler know that it has to make virtual calls, even though no class
 in the library overrides the method, because some app code might
 derive from the class and override the method? 

Foo foo = new Bar(); foo.blah(); // the compiler can be absolutely certain that foo refers to a Bar in this case -- andy
Apr 20 2004
parent reply Mike Hearn <mike navi.cx> writes:
On Tue, 20 Apr 2004 09:01:18 -0700, Andy Friesen wrote:
 Foo foo = new Bar();
 foo.blah(); // the compiler can be absolutely certain that foo refers to 
 a Bar in this case

No, it still sounds broken. class A { int somefunc() { return 1; } } extern A giveMeAnObject(); // link with a plugin that is supposed to subclass A A a = giveMeAnObject() a.somefun == 1; // true ------------- now in a shared library ----------------- class B : A { int somefunc() { return 2; } } A giveMeAnObject() { return new B(); } ------------------------------------------------------- The compiler when compiling the first binary will think nothing is subclassing A, so not make the methods virtual. Now the shared library cannot subclass A and return it using polymorphism. What am I missing here which makes this work? thanks -mike
Apr 21 2004
parent Andy Friesen <andy ikagames.com> writes:
Mike Hearn wrote:
 On Tue, 20 Apr 2004 09:01:18 -0700, Andy Friesen wrote:
 
Foo foo = new Bar();
foo.blah(); // the compiler can be absolutely certain that foo refers to 
a Bar in this case

No, it still sounds broken. class A { int somefunc() { return 1; } } extern A giveMeAnObject(); // link with a plugin that is supposed to subclass A A a = giveMeAnObject() a.somefun == 1; // true ------------- now in a shared library ----------------- class B : A { int somefunc() { return 2; } } A giveMeAnObject() { return new B(); } ------------------------------------------------------- The compiler when compiling the first binary will think nothing is subclassing A, so not make the methods virtual. Now the shared library cannot subclass A and return it using polymorphism. What am I missing here which makes this work?

In this example, the compiler is only sure that giveMeAnObject yields an A instance. (which is enough to inline any final methods A may have, but little else) As you said, this isn't enough for the compiler to be able to optimize the virtual call out. Come to think of it, this would probably be enough for the compiler if A was declared as a final class. In my example, the new operator was used directly, so the compiler had unambigious knowledge of the exact type of the object. The trick is that the D compiler is optimizing specific method calls, not marking a given method as being inlineable or not. -- andy
Apr 21 2004