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
andSpaceShip
inherit fromSprite
(as you might if this was a game), which has the same two methods, but is abstract. Now imagine some code like:Here we can say that the static type of
ship
isSprite
. The compiler won't let you pass it to a method that requires a paramter of typeSpaceShip()
, and it wouldn't let you call any method that's onSpaceShip
but notSprite
.However, the dynamic type is
SpaceShip
. What does that actually mean? It means that if you callship.collide(anotherShip)
, it will know to useSpaceShip.collide
instead ofAsteroid.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.
This will fail to compile, because the compiler will only pick a method based on the dynamic type of
ship
and the static type ofasteroid
, 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.