Thread overview
Multiple Dispatch in practice
Oct 22, 2008
bearophile
Oct 23, 2008
Sergey Gromov
Oct 23, 2008
bearophile
October 22, 2008
On the Lambda the Ultimate forum I have just found a nice article about Multiple Dispatch in Practice: http://homepages.mcs.vuw.ac.nz/~alex/files/MuscheviciPotaninTemperoNobleOOPSLA2008.pdf

I have seen that this topic was also discussed here: http://www.digitalmars.com/webnews/newsgroups.php?art_group=digitalmars.D&article_id=56018


This is normal D1 code that shows a manual implementation of double dispatch:

import std.stdio: writefln;

/// ...
template IsInstance(Class) {
    static assert(is(Class == class), "IsInstance: Class must be a class");

    bool IsInstance(TyObj)(TyObj obj) {
        return cast(Class)obj !is null;
    }
}

interface Vehicle {
    void collide(Vehicle v);
}

class Car : Vehicle {
    void collide(Vehicle v) {
        if (IsInstance!(Car)(v))
            writefln("Car hits car");
        else if (IsInstance!(Bike)(v))
            writefln("Car hits bike");
        else
            throw new Exception("missing case: should not happen");
    }
}

class Bike : Vehicle {
    void collide(Vehicle v) {
        if (IsInstance!(Car)(v))
            writefln("Bike hits car");
        else if (IsInstance!(Bike)(v))
            writefln("Bike hits bike");
        else
            throw new Exception("missing case: should not happen");
    }
}

void main() {
    Vehicle car = new Car();
    Vehicle bike = new Bike();

    car.collide(bike);  // Car hits bike
    car.collide(car);   // Car hits car
    bike.collide(car);  // Bike hits car
    bike.collide(bike); // Bike hits bike
}



With built-in multiple (double) dispatch the two classes become something similar to this:

class Car : Vehicle {
    void collide(Car c) {
        writefln("Car hits car");
    }
    void collide(Bike b) {
        writefln("Car hits bike");
    }
}

class Bike : Vehicle {
    void collide(Car c) {
        writefln("Bike hits car");
    }
    void collide(Bike b) {
        writefln("Bike hits bike");
    }
}

Bye,
bearophile
October 23, 2008
Tue, 21 Oct 2008 22:01:15 -0400,
bearophile wrote:
> This is normal D1 code that shows a manual implementation of double dispatch:
> 
> import std.stdio: writefln;
> 
> /// ...
> template IsInstance(Class) {
>     static assert(is(Class == class), "IsInstance: Class must be a class");
> 
>     bool IsInstance(TyObj)(TyObj obj) {
>         return cast(Class)obj !is null;
>     }
> }
> 
> interface Vehicle {
>     void collide(Vehicle v);
> }
> 
> class Car : Vehicle {
>     void collide(Vehicle v) {
>         if (IsInstance!(Car)(v))
>             writefln("Car hits car");
>         else if (IsInstance!(Bike)(v))
>             writefln("Car hits bike");
>         else
>             throw new Exception("missing case: should not happen");
>     }
> }
> 
> class Bike : Vehicle {
>     void collide(Vehicle v) {
>         if (IsInstance!(Car)(v))
>             writefln("Bike hits car");
>         else if (IsInstance!(Bike)(v))
>             writefln("Bike hits bike");
>         else
>             throw new Exception("missing case: should not happen");
>     }
> }
> 
> void main() {
>     Vehicle car = new Car();
>     Vehicle bike = new Bike();
> 
>     car.collide(bike);  // Car hits bike
>     car.collide(car);   // Car hits car
>     bike.collide(car);  // Bike hits car
>     bike.collide(bike); // Bike hits bike
> }

You overcomplicate.

import std.stdio;

void main() {
    Vehicle car = new Car();
    Vehicle bike = new Bike();

    car.collide(bike);  // Car hits bike
    car.collide(car);   // Car hits car
    bike.collide(car);  // Bike hits car
    bike.collide(bike); // Bike hits bike
}

interface Vehicle {
    void collide(Vehicle v);
    void onCollision(Car c);
    void onCollision(Bike b);
}

class Car : Vehicle {
    override void collide(Vehicle v)     {
        v.onCollision(this);
    }
    override void onCollision(Car c) {
        writefln("Car hits car");
    }
    override void onCollision(Bike b) {
        writefln("Bike hits car");
    }
}

class Bike : Vehicle {
    override void collide(Vehicle v)     {
        v.onCollision(this);
    }
    override void onCollision(Car c) {
        writefln("Car hits bike");
    }
    override void onCollision(Bike b) {
        writefln("Bike hits bike");
    }
}
October 23, 2008
Sergey Gromov:

> You overcomplicate.
> ...
> interface Vehicle {
>     void collide(Vehicle v);
>     void onCollision(Car c);
>     void onCollision(Bike b);
> }

You oversemplificate :-) You have had to modify the original interface. I'll not use your version of the code. Multiple dispatch allows you to not modify the original interface, keeping changes more localized. If Car manages 5 collisions, while Bike 7, and they share just 3 collisions, your interface and classes become quite hairy...

Bye,
bearophile