Object-Oriented Multiple Dispatch – Understanding Multiple Dispatch

multiple-dispatchobject-oriented

I've been reading around trying to understand multiple dispatching, and why it's so special.

On Wikipedia I came across this simple example:

 (defmethod collide-with ((x asteroid) (y asteroid))
   ;; deal with asteroid hitting asteroid
   )
 (defmethod collide-with ((x asteroid) (y spaceship))
   ;; deal with asteroid hitting spaceship
   )
 (defmethod collide-with ((x spaceship) (y asteroid))
   ;; deal with spaceship hitting asteroid
   )
 (defmethod collide-with ((x spaceship) (y spaceship))
   ;; deal with spaceship hitting spaceship
   )

What I don't understand however, is how it's different from just doing something like this:

class Asteroid {
  def collide(y: Asteroid)  = // deal with asteroid hitting asteroid
  def collide(y: SpaceShip) = // deal with asteroid hitting spaceship
}

class SpaceShip {
  def collide(y: Asteroid)  = // deal with spaceship hitting asteroid
  def collide(y: SpaceShip) = // deal with spaceship hitting spaceship
}

On the technical level, what is the difference? I know one uses multiple dispatch, and the other uses single dispatch with method overloading.

As I understand it, the visitor pattern is a solution to get around not having multiple dispatch in single-dispatch OOP languages, which just confuses me more since the overloading solution seems to be working just fine without employing this pattern.

So can someone explain the technical differences between doing one vs the other?

Best Answer

To understand the difference, there's one more piece of the puzzle you need to understand: dynamic dispatch.

Let's slightly modify your example by having both Asteroid and SpaceShip inherit from Sprite (as you might if this was a game), which has the same two methods, but is abstract. Now imagine some code like:

Sprite ship = new SpaceShip();

Here we can say that the static type of ship is Sprite. The compiler won't let you pass it to a method that requires a paramter of type SpaceShip(), and it wouldn't let you call any method that's on SpaceShip but not Sprite.

However, the dynamic type is SpaceShip. What does that actually mean? It means that if you call ship.collide(anotherShip), it will know to use SpaceShip.collide instead of Asteroid.collide or any other implementation. Using the dynamic type to choose which method to call is called "dynamic dispatch".


So, given that, the answer is that the second example you give can't handle multiple dispatch based on dynamic types. E.g.

Sprite ship = new SpaceShip();
Sprite asteroid = new Asteroid();
ship.collide(asteroid);

This will fail to compile, because the compiler will only pick a method based on the dynamic type of ship and the static type of asteroid, and it won't find one.


According to the Wikipedia article, the first example is from a language which will pick between those four methods with dynamic dispatch. If the second example was from some language which would pick between overloads on those two classes based on dynamic type, then it would also be multiple dynamic dispatch, and the difference that the article is trying to illustrate wouldn't exist. At that point the choice would be about more general design decisions as the other answers describe.