Sign in to follow this  
homojedi

double dispatch explanation.

Recommended Posts

homojedi    121
hey there i just came across the concept of double dispatching, and i am quite lost as to what it does, could someone explain to me in layman's terms what it does. i heard it was a good way for seperating what collided with what in a collision when all your colliding object inherit from the same class. metaphors and similes welcome. cheers

Share this post


Link to post
Share on other sites
stonemetal    288
Well to shine a bit of a light on it polymorphism is single dispatch(You can only be polymorphic on the object type). That is to say double dispatch is "double polymorphism" or being able to select a function based on two parameters instead of just one.

Edit: Note that only applies to C++ etc. some languages like lisp have multi dispatch baked in.

Share this post


Link to post
Share on other sites
homojedi    121
so polymorphism is single dispatch, and hence can decide what type an object parameter type is during run time. e,g


function( BaseEntity* entity )
{
entity.doStuff( )
}



and whatever entity you pass into that function as long as it inherits from BaseEntity will have it's version of the function called.

so.. double dispatching......What? two parameters instead of one? can you cook up a simple psuedo code example for me please?

cheers

Share this post


Link to post
Share on other sites
Evil Steve    2017
Quote:
Original post by homojedi
so.. double dispatching......What? two parameters instead of one? can you cook up a simple psuedo code example for me please?
Double Dispatch

Yes, it's using two parameters instead of one - except one is the this pointer.

Share this post


Link to post
Share on other sites
homojedi    121
hi guys,
thanks for the replies and apologies for the late one ive been a tad busy.
So from what i can glean form that wikipedia article, single dispatch is polymorphism as we know it and trying to provide different behaviours for different objects in the context of collision via overloading functions doesent work because although because of single dispatch the compiler knows at run time which function to call and execute, if however we pass a reference of a class that is declared of type parent class but we assign it a reference to a child class, the overloaded functions although the correct function in terms of which class it should be is called, the function within that class outputs the wrong message due to overloaded methods being static instead using the parent class from the parameter rather than looking up a virtual table and seeing that its actually a reference to the child type.

does that about sum that part up?

And as a solution to that,( using the wikipedia example ) we implement in both spaceship classes a virtual function that takes in an asteroid reference now, that on its own is still a static variable. but when we then call the asteroid.collidWith function it then performs dynamic lookup and get's the actual type and calls the correct function. so it essentially goes through a dispatch, then another, hence double dispatch?

cheers

Share this post


Link to post
Share on other sites
homojedi    121
Hey again, just thinking about the concept of double dispatch i cooked up my own little psuedo code to help solidify my understanding. So here we go

i have classes



class Player:base_entity;
class explodingThing:base_entity;
class World;

class Bullet:public base_entity
{
public:
virtual void collideWith( Player* );
{
cout<<"oh snap, you dead";
}
virtual void collidewith( explodingThing* )
{
cout<<"boom baby";
}
virtual void collideWith( World* );
{
cout<<"missed by a country mile";
}
}

class explodingBullet:public base_entity
{
public:
virtual void collideWith( Player* );
{
cout<<"oh snap, you dead";
}
virtual void collidewith( explodingThing* )
{
cout<<" oh shi-KABOOOOOM";
}
virtual void collideWith( World* );
{
cout<<"missed by a country mile";
}
}



and then i create variables


Player player;
explodingThing exthing;
explodingBullet exBullet;
Bullet bullet
World world;

base_entity *p_Abullet = new Bullet( );



and then call the functions collideWith on P_aBullet

p_Abullet.collidewith( player );
p_Abullet.collideWith( exthing );//calls bullets collision functions
p_Abullet.collideWith( world );

p_Abullet = new explodingBullet( );

p_Abullet.collidewith( player );
p_Abullet.collideWith( exthing );
p_Abullet.collideWith( world );//calls exploding bullets collision functions



and this should all work dandy...however if i were too

base_entity *p_exThing = new explodingThing( );

p_aBullet.collideWith( p_exThing );


wont work because the overloaded paramater is static and think's that the parameter is a base_entity which it doesent have an overloaded function for

to fix this i would have too, in both player and explodingthing

virtual void collidWith( base_entity* ent )
{
ent.collideWith( *this );
}



of course i havent accounted for a collision between player and exploding thing but it is psuedo code...well, sort of, but thats the general gist of it correct?

Share this post


Link to post
Share on other sites
rip-off    10976
Yes. C++ selects overloaded functions statically, and selects virtual methods based on a single runtime type. You need two polymorphic calls to select a function implementation based on two dynamic types.

I believe your psuedo code illustrates you understand the problem.

Quote:

to fix this i would have too, in both player and explodingthing

That is one way to do it. You do note that you must now implement this function in every derived class. You could alternatively use CRTP:

class World;
class Player;
class Explosion;

class Entity {
public:
virtual void collideWith(World&);
virtual void collideWith(Player &);
virtual void collideWith(Explosion &);

virtual void collideWith(Entity &other) = 0;
};

// Note: T must be derived from EntityCRTP!
template<class T>
class EntityCRTP : public Entity {
public:
virtual void collideWith(const Entity &other) {
// We could also choose to use dynamic_cast in debug mode, along with an assert()
T &t = static_cast<T&>(*this);
other.collideWith(t);
}
};

// This class now has a working implementation of collideWith(Entity)
class Player : public EntityCRTP<Player> {
public:
// ...
};



Also note that I'm using references instead of pointers. References can be used with polymorphic objects too, and they better express the intent of passing an existing object to a function.

Share this post


Link to post
Share on other sites
Zahlman    1682
Quote:
Original post by homojedi
so polymorphism is single dispatch


Not quite. Polymorphism is a concept; dispatch is what you do to make "calling a function" (or method, if you insist) behave polymorphically. 'single', 'double', etc. ('multiple', in general) describe what kind of dispatch is done, and it's a property of the language.

In many popular languages such as C++ and Java, the built-in dispatch that you get from calling 'virtual' functions (C++) or instance methods (Java) is single dispatch. The term "double dispatch" is also used to describe a technique whereby you implement double dispatch yourself by arranging for one single-dispatch (using the type of one object) to trigger a second single-dispatch (using the other object involved in the interaction).

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this