www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Multiple Dispatch in practice

reply bearophile <bearophileHUGS lycos.com> writes:
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
Oct 21 2008
parent reply Sergey Gromov <snake.scaly gmail.com> writes:
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"); } }
Oct 22 2008
parent bearophile <bearophileHUGS lycos.com> writes:
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
Oct 23 2008