delegate cannot handle polymorphism?

foobar foo at bar.com
Mon Jun 27 23:54:56 PDT 2011


== Quote from Nub Public (nubpublic at gmail.com)'s article
> On 6/28/2011 1:29 AM, Timon Gehr wrote:
> > Nub Public wrote:
> >> On 6/27/2011 7:08 PM, Michel Fortin wrote:
> >>> On 2011-06-27 03:30:09 -0400, Nub Public<nubpublic at gmail.com>  said:
> >>>
> >>>> class BOn 6/27/2011 7:08 PM, Michel Fortin wrote:
> >>> On 2011-06-27 03:30:09 -0400, Nub Public<nubpublic at gmail.com>  said:
> >>>
> >>>> class B
> >>>> {
> >>>> void fun() { writeln("B"); }
> >>>> }
> >>>>
> >>>> class D : B
> >>>> {
> >>>> override void fun() { writeln("D"); }
> >>>> }
> >>>>
> >>>> void delegate() dg =&b.fun;
> >>>> dg.ptr = cast(void*)d;
> >>>> dg();
> >>>>
> >>>>
> >>>> Compiler: DMD 2.053
> >>>> It prints "B" instead of "D".
> >>>> The equivalent code in C++ prints "D" nicely.
> >>>
> >>> C++ doesn't have delegates, and D doesn't have member function pointers.
> >>> Resolving virtual functions is done while you take its address in D,
> >>> while in C++ the member function pointer type contains holds the vtable
> >>> offset (or several in the case of multiple inheritance) which gets
> >>> resolved only when you call the function.
> >>>
> >>> If you want the C++ behaviour, try using a delegate literal as a
> >>> trampoline that gets the object as a parameter to then call your function:
> >>>
> >>> void delegate(B b) dg = (B b) { b.fun(); };
> >>>
> >>> dg(d);
> >>>
> >>
> >>
> >> Thank you. That was very helpful.
> >>
> >> What's the rational for this behavior though? Resolving the address of a
> >> virtual function at compile time seems a little counter-intuitive to me.
> >> I guess this way is slightly more efficient.
> >
> > A delegate literal consists of a function pointer and a context pointer. There is
> > no polymorphism in that. A member function is a normal function you can take the
> > address of.
> I see.
> > In general, you shouldn't update one of (ptr,funcptr) without updating the other
> > unless you have good reasons to do so and know exactly what you are doing.
> > Not having member pointers is AFAIK a direct consequence of the fact that nobody
> > uses them in C++ and almost nobody even knows that they exist.
> > Furthermore, their implementation is too involved, given their limited usefulness.
> >
> > Cheers,
> > -Timon
> I have to disagree on this.
> Member function pointers are useful in many event handling systems.
> Imagine a signal and slot system. To register a member function as a
> slot, the most direct and intuitive way is to take a member function
> pointer. In c++0x and boost, <function>, <functional> and related
> libraries all work with member function pointers.
> My premise is simple: a virtual function should always be resolved by
> the dynamic identity of the object, regardless of whether it is called
> directly or through a function pointer.
> Perhaps the contextptr of D delegate cannot do this because it can refer
> to the enclosing context besides an object. But I'd love it for D to
> have the functionality of a truly polymorhic member function pointer.
> Maybe the restrictions on the keyword "function" can be relaxed to work
> with such a pointer?

The above premise is incorrect in that it compares to different concepts. A
delegate is a closure whereas a c++ member function pointer is not. This means it
captures the context in which the code was run. In the case of a method call, that
context would be the specific instance when the delegate was created hence it
cannot and should not be polymorphic.

Regarding signal/slot designs: see for example C#'s implementation - this is
incorporated into the language as "events" which are simply arrays of delegates.
Implementing this via member function pointers is actually the uncommon case since
most other languages use closures.


More information about the Digitalmars-d mailing list