Topic: dynamic dispatching
Author: jules@REMOVETHIS.op59.net (Julian Smith)
Date: Sun, 1 Aug 2004 06:10:35 GMT Raw View
On Thu, 22 Jul 2004 18:53:38 GMT
bekkah@web.de (Helium) wrote:
> There already is a proposal for dynamic dispatchign (n1463). Well, I
> don't like this proposal too much. This is why I want to propose an
Just a quick note to mention that there is a later version of the
multimethods proposal, document number n1529, which can be found at:
http://std.dkuug.dk/jtc1/sc22/wg21/docs/papers/2003/n1529.html
- Julian
--
http://www.op59.net
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: AlbertoBarbati@libero.it (Alberto Barbati)
Date: Mon, 26 Jul 2004 17:04:04 GMT Raw View
Helium wrote:
>>
>>The problem with this syntax is that the multimethod is only implictly
>>declared, while N1463 made the declaration explicit. With your syntax,
>>when the compiler sees
>>
>> void foo (Base & x, Base & y) {...}
>>
>>how many parameters require dynamically dispatching? Two? Zero? One?
>>Which one? The compiler must make the decision immediately, it cannot
>>defer the decision until it encounters the definition of the dynamic
>>overload. What if there aren't any?
>
> Why? Can't the compiler wait until it sees the overloaded versions?
>
That would be the first time in C++ where the semantic of a construct
cannot be determined until the end of a compilation unit. Not that it
cannot be done, but looks like a Pandora's box to me. You will have to
provide compiler vendors a very good reason to make them consider that.
Moreover, consider this example, with your syntax:
a.h:
#include "Base.h" // includes definition of Base
// declaration only, is it a multimethod or not?
void foo (Base & x);
a.cpp:
#include "Derived.h" // includes definitions of Base and Derived
// implementation makes foo a multimethod
void foo (Base & Derived x) { ... }
b.cpp:
#include "a.h"
void bar (Base& x)
{
foo (x); // static or dynamic dispatch???
}
This code looks like a reasonable use case to me. With your syntax,
either the decision to select between static or dynamic dispatch is
deferred to link-time or the program is defined to be ill-formed. No
feature in current C++ *requires* link-time code generation (not even
"export" AFAICT), so it looks very difficult to me that such a feature
have a chance to be considered.
However, if the declaration in a.h had the keyword "virtual" the
compiler would have no doubt and could select dynamic dispatch at
compile-time.
> But you could use somthing similar to N1463:
>
> void foo (virtual Base & x) {...}
>
> void foo (Base & Derived1 x) {...}
> void foo (Base & Derived2 x) {...}
> void foo (Base & Derived3 x) {...}
>
I don't see the advantage of repeating "Base &" in every implementation
function, unless you allow "overloading" such as
void foo (virtual Base1 & x) {...}
void foo (virtual Base2 & x) {...}
(which is similar to what you proposed originally, right?). As I said in
my previous post, I don't think there's a real need for such complexity,
but that's my personal opinion.
>>
>>This is in fact an advantage, but it is worth the effort? Multimethods
>>are already complex, do we need to (statically) overload a multimethod?
>>Maybe the N1463 could be improved to allow this, if it's needed.
>
> Do you mean complex to the compiler or complex to the user?
>
For the user.
>
>
> Anyway, what about this:
>
> struct Base {};
> struct Derived1 : Base {};
> struct Derived2 : Base {};
>
> struct Foo {
> void foo (virtual Base &);
> };
>
> struct Bar : Foo {
> void foo (Derived1 &);
> void foo (Derived2 &);
> };
>
> [...]
>
> What is called? Is it allowed?
> Should I change Foo::foo to be virtual to get a dynamic dispatch you
> could expect if you see the code above?
N1463 deliberately omits the case of member functions. I agree with the
rationale contained there. Your example sopports that rationale.
Regards,
Alberto
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: bekkah@web.de (Helium)
Date: Thu, 22 Jul 2004 18:53:38 GMT Raw View
There already is a proposal for dynamic dispatchign (n1463). Well, I
don't like this proposal too much. This is why I want to propose an
alternative.
Normaly functionarguments have a static type:
void foo (Type & x) {...}
Any kind of dispatching is a very unconvenient task.
So I propose the posibility to have a dynamic type next to the static
type we already have. Only pointer and references can refere to an
object of a derived type, so a dynamic type is only usefull with
these. The synthax should look like this:
void foo (Base & x) {...} // some kind of fallback
void foo (Base & Derived1 x) {...}
void foo (Base & Derived2 x) {...}
void foo (Base & Derived3 x) {...}
..
The first line shows a normaly function definition, which is used as
some kind of fallback here, which is used if there is no dynamic
overloaded version that fits better. Its determined at runtime which
of these functions is called.
The return type of a dynamic overloaded version is covariant to the
fallback-version.
Base & foo (Base & x);
Derived & foo (Based & Derived x);
Here an example of how to use the dynamic dispatching:
struct Shape {...};
struct Square : Shape {...};
struct Triangle : Shape {...};
bool overlap (Shape & a, Shape & b) {...}
bool overlap (Shape & Square a, Shape & Triangle b) {...}
bool overlap (Shape & Triangle a, Shape & Square b) {...}
I think the synthax I propose is a lot mor clear than that of n1463.
And its more powerfull as you can do things like this:
class Base1 {}
class Base2 {}
class Derived1FromBase1 : public Base1 {}
class Derived2FromBase1 : public Base1 {}
class Derived1FromBase2 : public Base2 {}
class Derived2FromBase2 : public Base2 {}
void func (Base1 & Derived1FromBase1 x)
{...}
void func (Base1 & Derived2FromBase1 x)
{...}
void func (Base2 & Derived1FromBase2 x)
{...}
void func (Base2 & Derived2FromBase2 x)
{...}
So you can do:
Base1 * b1 = new Derived2FromBase1;
func (*b1);
Base2 * b2 = new Derived1FromBase2();
func (*b2);
So I've combined static overloading and dynamic dispatching.
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: AlbertoBarbati@libero.it (Alberto Barbati)
Date: Fri, 23 Jul 2004 16:12:19 GMT Raw View
Helium wrote:
> The synthax should look like this:
>
>
> void foo (Base & x) {...} // some kind of fallback
>
> void foo (Base & Derived1 x) {...}
> void foo (Base & Derived2 x) {...}
> void foo (Base & Derived3 x) {...}
> ..
>
The problem with this syntax is that the multimethod is only implictly
declared, while N1463 made the declaration explicit. With your syntax,
when the compiler sees
void foo (Base & x, Base & y) {...}
how many parameters require dynamically dispatching? Two? Zero? One?
Which one? The compiler must make the decision immediately, it cannot
defer the decision until it encounters the definition of the dynamic
overload. What if there aren't any?
>
> I think the synthax I propose is a lot mor clear than that of n1463.
> And its more powerfull as you can do things like this:
>
> class Base1 {}
> class Base2 {}
> class Derived1FromBase1 : public Base1 {}
> class Derived2FromBase1 : public Base1 {}
> class Derived1FromBase2 : public Base2 {}
> class Derived2FromBase2 : public Base2 {}
>
> void func (Base1 & Derived1FromBase1 x)
> {...}
>
> void func (Base1 & Derived2FromBase1 x)
> {...}
>
> void func (Base2 & Derived1FromBase2 x)
> {...}
>
> void func (Base2 & Derived2FromBase2 x)
> {...}
>
This is in fact an advantage, but it is worth the effort? Multimethods
are already complex, do we need to (statically) overload a multimethod?
Maybe the N1463 could be improved to allow this, if it's needed.
As I am talking about improving the syntax in N1463, I think I see a way
to avoid the ugly "_" hack. Let's declare the dispatch function as
proposed in N1463, for example:
bool Overlap(virtual Shape& a, virtual Shape& b);
then declare the implementation functions with template-like syntax,
like this:
bool Overlap<Square, Triangle>(Square& a, Triangle& b) {...}
bool Overlap<Triangle, Square>(Triangle& a, Square& b) {...}
of course, as the type of the parameters can be deduced from the
context, they can be omitted, leading to a cleaner syntax:
bool Overlap<>(Square& a, Triangle& b) {...}
bool Overlap<>(Triangle& a, Square& b) {...}
This syntax solves the problem where one wants to define an
implementation function that takes the exact parameters of the dispatch
function, such as:
bool Overlap<>(Shape& a, Shape& b) {...}
Moreover, this syntax also allows implementation functions to be called
with static dispatching, as in:
bool result = Overlap(shape1, shape2); // dynamic dispatch
bool result = Overlap<Square, Triangle>(shape1, shape2); // static
dispatch
notice that the types to be used for static dispatch are to be specified
explicitly, allowing for strict type checking of the parameters. Maybe a
relaxed syntax like:
bool result = Overlap<>(shape1, shape2); // static dispatch
that deduces the type from the static type of the parameters could also
be allowed, but I found the explicit syntax clearer and less error-prone.
My two eurocents
Alberto
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: bekkah@web.de (Helium)
Date: Sat, 24 Jul 2004 19:32:00 GMT Raw View
> > The synthax should look like this:
> >
> >
> > void foo (Base & x) {...} // some kind of fallback
> >
> > void foo (Base & Derived1 x) {...}
> > void foo (Base & Derived2 x) {...}
> > void foo (Base & Derived3 x) {...}
> > ..
> >
>
> The problem with this syntax is that the multimethod is only implictly
> declared, while N1463 made the declaration explicit. With your syntax,
> when the compiler sees
>
> void foo (Base & x, Base & y) {...}
>
> how many parameters require dynamically dispatching? Two? Zero? One?
> Which one? The compiler must make the decision immediately, it cannot
> defer the decision until it encounters the definition of the dynamic
> overload. What if there aren't any?
Why? Can't the compiler wait until it sees the overloaded versions?
But you could use somthing similar to N1463:
void foo (virtual Base & x) {...}
void foo (Base & Derived1 x) {...}
void foo (Base & Derived2 x) {...}
void foo (Base & Derived3 x) {...}
> > I think the synthax I propose is a lot mor clear than that of n1463.
> > And its more powerfull as you can do things like this:
> >
> > class Base1 {}
> > class Base2 {}
> > class Derived1FromBase1 : public Base1 {}
> > class Derived2FromBase1 : public Base1 {}
> > class Derived1FromBase2 : public Base2 {}
> > class Derived2FromBase2 : public Base2 {}
> >
> > void func (Base1 & Derived1FromBase1 x)
> > {...}
> >
> > void func (Base1 & Derived2FromBase1 x)
> > {...}
> >
> > void func (Base2 & Derived1FromBase2 x)
> > {...}
> >
> > void func (Base2 & Derived2FromBase2 x)
> > {...}
> >
>
> This is in fact an advantage, but it is worth the effort? Multimethods
> are already complex, do we need to (statically) overload a multimethod?
> Maybe the N1463 could be improved to allow this, if it's needed.
Do you mean complex to the compiler or complex to the user?
> As I am talking about improving the syntax in N1463, I think I see a way
> to avoid the ugly "_" hack. Let's declare the dispatch function as
> proposed in N1463, for example:
>
> bool Overlap(virtual Shape& a, virtual Shape& b);
>
> then declare the implementation functions with template-like syntax,
> like this:
>
> bool Overlap<Square, Triangle>(Square& a, Triangle& b) {...}
> bool Overlap<Triangle, Square>(Triangle& a, Square& b) {...}
>
> of course, as the type of the parameters can be deduced from the
> context, they can be omitted, leading to a cleaner syntax:
>
> bool Overlap<>(Square& a, Triangle& b) {...}
> bool Overlap<>(Triangle& a, Square& b) {...}
>
> This syntax solves the problem where one wants to define an
> implementation function that takes the exact parameters of the dispatch
> function, such as:
>
> bool Overlap<>(Shape& a, Shape& b) {...}
>
> Moreover, this syntax also allows implementation functions to be called
> with static dispatching, as in:
>
> bool result = Overlap(shape1, shape2); // dynamic dispatch
>
> bool result = Overlap<Square, Triangle>(shape1, shape2); // static
> dispatch
>
> notice that the types to be used for static dispatch are to be specified
> explicitly, allowing for strict type checking of the parameters. Maybe a
> relaxed syntax like:
>
> bool result = Overlap<>(shape1, shape2); // static dispatch
>
> that deduces the type from the static type of the parameters could also
> be allowed, but I found the explicit syntax clearer and less error-prone.
>
This version has the advantage that you can statically dispatch. I
like it.
Anyway, what about this:
struct Base {};
struct Derived1 : Base {};
struct Derived2 : Base {};
struct Foo {
void foo (virtual Base &);
};
struct Bar : Foo {
void foo (Derived1 &);
void foo (Derived2 &);
};
What happens here:
Bar bar;
Foo & foo = bar;
Derived1 derived;
Base & base = derived;
foo.foo (base);
What is called? Is it allowed?
Should I change Foo::foo to be virtual to get a dynamic dispatch you
could expect if you see the code above?
struct Foo {
virtual void foo (virtual Base &);
};
-- Matthias Becker
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]