Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > C++ > double dispatch example

Reply
Thread Tools

double dispatch example

 
 
j j
Guest
Posts: n/a
 
      06-09-2012
Hi

I'm trying to understand the double dispatch mechanism. Below is my
simple program.
Please let me know whether this is good double dispatch example. In
case
it is missing something please let me know what is it.

thanks in advance

#include <iostream>

using namespace std;

class X;

class A
{
public:
virtual void fun(X &x)
{
cout << "A::fun" << endl;
}
};

class B : public A
{
public:
void fun(X &x)
{
cout << "B::fun" << endl;
}
};

class X
{
public:
virtual void fun(A &a)
{
cout << "X::fun" << endl;
a.fun(*this); // second dispatch
}
};

class Y : public X
{
public:
void fun(A &a)
{
cout << "Y::fun" << endl;
a.fun(*this); // second dispatch
}
};

int main(void)
{
B b;

Y y;
X &x = y;
x.fun(b); // first dispatch

return 0;
}
 
Reply With Quote
 
 
 
 
Pavel
Guest
Posts: n/a
 
      06-09-2012
j j wrote:
> Hi
>
> I'm trying to understand the double dispatch mechanism. Below is my
> simple program.
> Please let me know whether this is good double dispatch example. In
> case
> it is missing something please let me know what is it.
>
> thanks in advance
>
> #include<iostream>
>
> using namespace std;
>
> class X;
>
> class A
> {
> public:
> virtual void fun(X&x)
> {
> cout<< "A::fun"<< endl;
> }
> };
>
> class B : public A
> {
> public:
> void fun(X&x)
> {
> cout<< "B::fun"<< endl;
> }
> };
>
> class X
> {
> public:
> virtual void fun(A&a)
> {
> cout<< "X::fun"<< endl;
> a.fun(*this); // second dispatch
> }
> };
>
> class Y : public X
> {
> public:
> void fun(A&a)
> {
> cout<< "Y::fun"<< endl;
> a.fun(*this); // second dispatch
> }
> };
>
> int main(void)
> {
> B b;
>
> Y y;
> X&x = y;
> x.fun(b); // first dispatch
>
> return 0;
> }

It is a moot question. C++ does not have internal support for multiple dispatch
(common lisp does).

Your example is, however, by and large what some people call "Double-dispatch"
in C++ -- but I do not think it is correct. It is funny how Wikipedia article on
"Double dispatch" at http://en.wikipedia.org/wiki/Double_dispatch essentially
repeats your design whereas the article on multiple dispatch at
http://en.wikipedia.org/wiki/Multiple_dispatch rightly explains that C++ only
supports single dispatch directly (Common Lisp supports multiple dynamic
dispatch) and illustrates how you could "do it yourself" in Java, C and C++.
Their first example in C++ is analogous to that in Java and both are quite lame.
Their second example in C++ is better but still has serious problems I will stop
at later. Their best example is IMHO that is given for C language (it could be
of course used in C++, too, even with few additional perks).

More specifically, my feeling is that your design suffers from two fundamental
issues:

1. Incorrect encapsulation target (Wikipedia C++ examples suffer from same).
With multiple (in particular, double) dispatch, the behavior of a combination of
several dynamic types does not belong to either of them. It should be
encapsulated in an separate entity (that is sometimes called MultiMethod).

2. An arbitrary choice of having 2 class hierarchies (did you feel you needed 2
hierarchies as you wanted double-dispatch? You are not alone. The authors of
Wikipedia's "Double Dispatch" article apparently felt same).

As usual, a litmus test for the design quality is to change the user
requirements. Try to satisfy this simple set of requirements with your design:

- when X is having fun with A, the required behavior is to print "ABC"
- when X is having fun with B, the required behavior is to print "DEF"
- when Y is having fun with A *or* B, the required behavior is to print "GHI"

Below is my version of the solution:

------------cut here-----------
#include <iostream>
#include <typeinfo>
#include <vector>

using namespace std;

template <class T>
class FunTicketHolder {
public:
static int ticket() { return ticket_; }
static void ticket(int t) { ticket_ = t; }
private:
static int ticket_;
};

template<class T>
int FunTicketHolder<T>::ticket_ = -1;

class FunLover {
public:
virtual int funClassRegId() const = 0;
};

ostream&
operator<<(ostream &os, const FunLover &x) {
os << typeid(x).name() << '(' << (const void*)&x << ')';
}

class A: public FunLover, public FunTicketHolder<A> {
virtual int funClassRegId() const { return ticket(); }
};

class B: public FunLover, public FunTicketHolder<B> {
virtual int funClassRegId() const { return ticket(); }
};

class X: public FunLover, public FunTicketHolder<X> {
virtual int funClassRegId() const { return ticket(); }
};

class Y: public FunLover, public FunTicketHolder<Y> {
virtual int funClassRegId() const { return ticket(); }
};

class DoubleDispatchedFun {
typedef void (*FunFuncPt)(FunLover &, FunLover &);
public:
void operator()(FunLover &x, FunLover &y) {
cout << "Fun lovers " << x << " and " << y << " are ";
if(!areRegisteredForFun(x, y)) {
cout << "missing all the fun:\nThey forgot to register!" << endl;
return;
}
cout << "having their fun:\n";
funRegistry_[x.funClassRegId()][y.funClassRegId()](x, y);
}
template <class X, class Y>
void registerForFun(FunFuncPt fun) {
int xIdx = checkInFunLoverClass<X>();
int yIdx = checkInFunLoverClass<Y>();
letAnyFunLoverBeFirst(xIdx, yIdx);
FunFuncPt oldFun = funRegistry_[xIdx][yIdx];
if (!fun)
if(oldFun)
cout << "Changed your mind? No problem!" << endl;
else
cout << "You are not funny!" << endl;
else
if(oldFun)
if(oldFun == fun)
cout << "You've got it already registered" << endl;
else
cout << "You want it another way? No problem!" << endl;
else
cout << "Welcome to fun-lover club, " << typeid(X).name() <<
" and " << typeid(Y).name() << '!' << endl;
funRegistry_[xIdx][yIdx] = fun;
funRegistry_[yIdx][xIdx] = fun;
}
private:
bool areRegisteredForFun(FunLover &x, FunLover &y) {
return x.funClassRegId() >= 0 &&
x.funClassRegId() < funRegistry_.size() &&
y.funClassRegId() >= 0 &&
y.funClassRegId() < funRegistry_[x.funClassRegId()].size() &&
funRegistry_[x.funClassRegId()][y.funClassRegId()] != 0;
}
template <class X>
int checkInFunLoverClass() {
if(X::ticket() >= 0)
return X::ticket();
X::ticket(funRegistry_.size());
funRegistry_.resize(X::ticket() + 1);
return X::ticket();
}
void letAnyFunLoverBeFirst(int xIdx, int yIdx) {
letFirstBeFirst(xIdx, yIdx);
letFirstBeFirst(yIdx, xIdx);
}
void letFirstBeFirst(int firstIdx, int secondIdx) {
int sizeAtFirstIdx = funRegistry_[firstIdx].size();
if(secondIdx >= sizeAtFirstIdx)
funRegistry_[firstIdx].resize(secondIdx + 1);
}
vector<vector<FunFuncPt> > funRegistry_;
};

void
printABC(FunLover &, FunLover &) {
cout << "ABC" << endl; // fun shall be flushed!
}
void
printDEF(FunLover &, FunLover &) {
cout << "DEF" << endl; // fun shall be flushed!
}
void
printGHI(FunLover &, FunLover &) {
cout << "GHI" << endl; // fun shall be flushed!
}

int
main(int, char*[])
{
DoubleDispatchedFun ddFun;

// register double-dispatchable classes; this is
// separated so that you could register fun loving
// classes dynamically, in different modules
ddFun.registerForFun<X, A>(printABC);
ddFun.registerForFun<X, B>(printDEF);
ddFun.registerForFun<Y, A>(printGHI);
ddFun.registerForFun<Y, B>(printGHI);

// all these individuals...
A realA;
B realB;
X realX;
Y realY;

// are fun-lovers
FunLover &x = realX;
FunLover &y = realY;
FunLover &a = realA;
FunLover &b = realB;

// let's the fun begin!
ddFun(x, a);
ddFun(x, b);
ddFun(y, a);
ddFun(y, b);
ddFun(b, y); // just for the heck of it, let's change positions..
ddFun(x, y); // We do not mind x's having fun with y..
ddFun(x, x); // or itself.. as long as it is a registered fun.

return 0;
}

------------cut here-----------


-Pavel
 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
multi/double dispatch, multifunctions once again AndyL Python 1 02-16-2006 09:41 AM
php to python dynamic dispatch example todddeluca@gmail.com Python 0 12-18-2005 07:45 PM
Visitor Pattern, Deep Copy & Double Dispatch Thomas Matthews C++ 1 02-21-2005 08:50 PM
cannot convert parameter from 'double (double)' to 'double (__cdecl *)(double)' error Sydex C++ 12 02-17-2005 06:30 PM
[ANN] doublecpp -- double dispatch in C++ Lorenzo Bettini C++ 0 07-26-2003 01:21 AM



Advertisments