 |
C++Talk.NET C++ language newsgroups
|
| View previous topic :: View next topic |
| Author |
Message |
Dylan Nicholson Guest
|
Posted: Wed Mar 03, 2004 11:49 am Post subject: multimethods - possible implementation |
|
|
I was reading through some of the proposals for adding multimethods to
C++, including implementation details that talked a lot about RTTI
etc. etc., and O(N) call times depending on the number of multimethods
defined.
But surely there is a simple O(1) method that doesn't use RTTI at all,
providing that you can modify the vtable of a class on the fly (which
of course a compiler can do).
So for instance if an initial class definition is:
struct object
{
virtual ~object() { }
};
It contains a vtable with just the one entry.
Suppose the compiler then encounters the following function
declaration:
void interact(virtual object*, virtual object*);
It could then add a further function to the vtable, something like:
virtual __interact(object* obj) { interact(this, obj); }
(Of course for many compilers, it may be possible to point the vtable
entry directly to the standalone 'interact' function).
It then comes across the following:
struct square : object
{
int x;
int y;
int width;
};
struct circle : object
{
int x;
int y;
int radius;
};
void interact(virtual square* sqr, virtual circle* crc);
At this point, it needs to add a new entry to object's vtable like so:
virtual __interact1(circle* crc) { interact(this, crc); }
Then override this in square:
virtual __interact1(circle* crc) { interact(this, crc); }
And override circle's __interact entry:
virtual __interact(object* obj) { obj->__interact1(this); }
It might then encounter:
struct triangle : object
{
/* whatever */
};
void interact(virtual triangle* crc, virtual circle* tri);
This would only require overriding __interact in triangle's vtable:
virtual __interact1(circle* crc) { interact(this, crc); }
Now when an actual call to
interact(obj1, obj2)
is encountered in the code, this is translated as:
obj1->__interact(obj2);
So that if obj1 is a square, it will call
obj2->__interact1(obj1)
Which is obj2 is a circle, will call
void interact(virtual square* sqr, virtual circle* crc);
Likewise, if obj1 is a triangle, it will call
void interact(virtual triangle* tri, virtual circle* crc);
as expected. In any other circumstance, it would call the original
interact(object*, object*) function (which I suppose could be
undefined, thus generate a 'pure virtual function call' exception or
some such).
I haven't thought it much through for more than 2 virtual parameters,
but it would seem to follow a similar (if more complex) pattern.
I take it this isn't under serious consideration for inclusion in the
standard at this point, but is there much interest in it?
Dylan
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
Julian Smith Guest
|
Posted: Wed Mar 03, 2004 8:28 pm Post subject: Re: multimethods - possible implementation |
|
|
On 3 Mar 2004 06:49:55 -0500
[email]wizofaus (AT) hotmail (DOT) com[/email] (Dylan Nicholson) wrote:
| Quote: | I was reading through some of the proposals for adding multimethods to
C++, including implementation details that talked a lot about RTTI
etc. etc., and O(N) call times depending on the number of multimethods
defined.
But surely there is a simple O(1) method that doesn't use RTTI at all,
providing that you can modify the vtable of a class on the fly (which
of course a compiler can do).
|
One practical problem is that, if there are more than one compilation units,
your idea requires changes to vtables and adding new virtual functions to
classes, at link time. This is certainly possible, but I suspect that making
life even more difficult for implementors wouldn't go down particularly well.
The other problem is more subtle. If I understand your suggestion properly,
it's basically getting the compiler to create double-dispatch code
automatically. But double dispatch has slightly different semantics from
C++'s overload-resolution (which is extended to dynamic types in the
multimethods extension proposal), because double dispatch dispatches on the
dynamic types of the parameters in order, where as C++'s overload resolution
treats all parameters equally.
Double dispatch has the advantage that it doesn't give `ambiguous dispatch'
errors, but it's arguably better to mimic C++'s existing static dispatch
semantics.
The proposal (http://std.dkuug.dk/jtc1/sc22/wg21/docs/papers/2003/n1529.html)
talks about a different way of getting constant time dispatch. This works by
defining small integers to uniquely identify classes, and using them to index
into a dispatch array. Ultimately it's doing much the same thing as your
idea, just putting the dispatch information in a different place - tying
(multi-dimensional) vtables to multimethod functions instead of classes. It
suffers from the same problem in that it requires work at link time, but it's
actually possible to do things even later, at runtime, which makes it pretty
easy to implement.
| Quote: |
So for instance if an initial class definition is:
struct object
{
virtual ~object() { }
};
It contains a vtable with just the one entry.
Suppose the compiler then encounters the following function
declaration:
void interact(virtual object*, virtual object*);
It could then add a further function to the vtable, something like:
virtual __interact(object* obj) { interact(this, obj); }
(Of course for many compilers, it may be possible to point the vtable
entry directly to the standalone 'interact' function).
It then comes across the following:
|
[...]
| Quote: | I haven't thought it much through for more than 2 virtual parameters,
but it would seem to follow a similar (if more complex) pattern.
|
I think double dispatch can be extended to more two parameters, but I've
never tried it.
| Quote: |
I take it this isn't under serious consideration for inclusion in the
standard at this point, but is there much interest in it?
|
Actually, I'm not particularly hopeful about getting multimethods into C++ at
all - there doesn't seem to be a particularly large amount of interest in the
C++ community, and most of the effort in the committee seems to be focused on
much simpler proposals and improving support for generic programming.
- Julian
--
http://www.op59.net
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
Ben Hutchings Guest
|
Posted: Wed Mar 03, 2004 8:50 pm Post subject: Re: multimethods - possible implementation |
|
|
Dylan Nicholson wrote:
| Quote: | I was reading through some of the proposals for adding multimethods to
C++, including implementation details that talked a lot about RTTI
etc. etc., and O(N) call times depending on the number of multimethods
defined.
But surely there is a simple O(1) method that doesn't use RTTI at all,
providing that you can modify the vtable of a class on the fly (which
of course a compiler can do).
snip |
Your method doesn't seem to allow separate compilation - the compiler
needs to know about all derived classes of the second polymorphic
class type in a multimethod when generating vtables for derived
classes of the first.
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
Dylan Nicholson Guest
|
Posted: Thu Mar 04, 2004 2:10 pm Post subject: Re: multimethods - possible implementation |
|
|
Ben Hutchings <do-not-spam-benh (AT) bwsint (DOT) com> wrote
| Quote: | Dylan Nicholson wrote:
I was reading through some of the proposals for adding multimethods to
C++, including implementation details that talked a lot about RTTI
etc. etc., and O(N) call times depending on the number of multimethods
defined.
But surely there is a simple O(1) method that doesn't use RTTI at all,
providing that you can modify the vtable of a class on the fly (which
of course a compiler can do).
snip
Your method doesn't seem to allow separate compilation - the compiler
needs to know about all derived classes of the second polymorphic
class type in a multimethod when generating vtables for derived
classes of the first.
|
Well, no, it would essentially have to build the final vtable
structure at link-time, and indeed ideally support it dynamically at
runtime, when loading shared libraries etc. I'm not pretending that
my suggestion is at all simple to implement, but at least it doesn't
suffer from the limitations of requiring RTTI.
Dylan
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
Dylan Nicholson Guest
|
Posted: Thu Mar 04, 2004 2:11 pm Post subject: Re: multimethods - possible implementation |
|
|
Julian Smith <jules (AT) REMOVETHIS (DOT) op59.net> wrote
| Quote: | On 3 Mar 2004 06:49:55 -0500
[email]wizofaus (AT) hotmail (DOT) com[/email] (Dylan Nicholson) wrote:
The other problem is more subtle. If I understand your suggestion properly,
it's basically getting the compiler to create double-dispatch code
automatically. But double dispatch has slightly different semantics from
C++'s overload-resolution (which is extended to dynamic types in the
multimethods extension proposal), because double dispatch dispatches on the
dynamic types of the parameters in order, where as C++'s overload resolution
treats all parameters equally.
I thought about this, I'm pretty sure that you could have both (e.g.): |
void interact(virtual square* sqr, virtual circle* crc); //[1]
and
void interact(virtual circle* crc, virtual square* sqr); //[2]
This would mean that object's vtable has
__interact1(virtual circle* crc);
&
__interact3(virtual square* sqr);
Then square would override with:
__interact1(virtual square* sqr) { interact(this, sqr); } // call [1]
& circle would override with:
__interact3(virtual square* crc) { interact(this, crc); } // call [2]
Dylan
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
Lorenzo Bettini Guest
|
Posted: Fri Mar 05, 2004 10:28 am Post subject: Re: multimethods - possible implementation |
|
|
Hi
I developed doublecpp:
Doublecpp is a preprocessor for C++ that handles a new linguistic
construct for defining branches of a multi-method. The "right" branch
of such a method will be selected dynamically at run-time according to
the actual type of the object on which the method is invoked and to the
actual type of the first argument: double dispatch.
http://www.lorenzobettini.it/software/doublecpp/index.html
Doublecpp is free software; you are free to use, share and modify it
under the terms of the GNU General Public License (see COPYING).
The double dispatch is performed in *constant* time O(1), since it uses
dynamic binding twice (with a technique similar to the Visitor pattern).
Lorenzo
--
+-----------------------------------------------------+
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
Ben Hutchings Guest
|
Posted: Fri Mar 05, 2004 10:32 am Post subject: Re: multimethods - possible implementation |
|
|
Dylan Nicholson wrote:
| Quote: | Ben Hutchings <do-not-spam-benh (AT) bwsint (DOT) com> wrote in message
news:<slrnc4c8tj.okv.do-not-spam-benh (AT) shadbolt (DOT) i.decadentplace.org.uk>...
Dylan Nicholson wrote:
I was reading through some of the proposals for adding multimethods to
C++, including implementation details that talked a lot about RTTI
etc. etc., and O(N) call times depending on the number of multimethods
defined.
But surely there is a simple O(1) method that doesn't use RTTI at all,
providing that you can modify the vtable of a class on the fly (which
of course a compiler can do).
snip
Your method doesn't seem to allow separate compilation - the compiler
needs to know about all derived classes of the second polymorphic
class type in a multimethod when generating vtables for derived
classes of the first.
Well, no, it would essentially have to build the final vtable
structure at link-time, and indeed ideally support it dynamically at
runtime, when loading shared libraries etc.
|
It's worse than that - the dynamic linker would have to modify
vtable pointers in existing objects and virtual function calls
in the code as the vtables expanded. This is simply not going
to work in the presence of dynamic linking.
| Quote: | I'm not pretending that my suggestion is at all simple to implement,
but at least it doesn't suffer from the limitations of requiring
RTTI.
|
I can see that it could be faster where it is applicable, but not
necessarily by that much. The speed of modern processors depends on
prediction of changes of control flow. The targets of virtual
function calls are often predicted wrongly and so are relatively slow
on average. The time taken to search a list of candidates (if
implemented by well-tuned code and not just an add-on written in C++)
and then make one indirect function call may be comparable to the cost
of the two virtual function calls.
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
|