UP | HOME

multiple dispatch

In Java and C++ we have single dispatch, or runtime polymorphism. So if we have two Animal pointers to two objects, a dog and a cat, calling dog->makeSound() will produce a bark and cat->makeSound() will produce a meow at run-time. In C++, this is done using virtual functions that allow for late binding. That is, the function being called is determined at run-time according to the object type doing the calling.

But what if we wanted to do something like runtime polymorphism on the arguments of a function? That is, what if we wanted to do something like: interact(Animal a1, Animal a2) where the a1 and a2 objects are both specific types of animals, e.g. dog and cat. We can't do this in Java and C++ out of the box, but we can in Julia.

1. visitor pattern

If we want to do this in C++, we can use the visitor pattern. Consider the case when you want to take the intersection between shapes. Then, we want to be able to call shape1.intersect(shape2) and have the behavior be determined by the types of shape1 and shape2. We will do that in two steps. First, shape1 will call it's own version of intersect() via single dispatch. Then, in that function, it will call shape2's version of intersect via single dispatch again, this time passing shape1 as an argument. The key here is that when we pass shape1 as an argument, this time it is typed as a specific shape, e.g. a Rectangle.

The implementation looks something like this:

class Shape{
public:
    virtual std::string name() const {
        return typeid(*this).name();
    }

    virtual void Intersect(const Shape*) const = 0;

    virtual void IntersectWith(const Shape*) const {}
    virtual void IntersectWith(const Rectangle*) const {}
    virtual void IntersectWith(const Ellipse*) const {}
};

Then, the Rectangle and Ellipse classes would be:

class Rectangle : public Shape {
    public:
        virtual void Intersect(const Shape* s) const {
            s->IntersectWith(this);
        }
};

class Ellipse : public Shape {
    public:
        virtual void IntersectWith(const Rectangle* r) const {
            std::cout << "Ellipse x Rectangle";
        }
};

Then

std::unique_ptr<Shape> pr(new Rectangle);
std::unique_ptr<Shape> pe(new Ellipse);
pr->Intersect(pe.get());

will result in

Ellipse x Rectangle

2. sources

Created: 2024-07-15 Mon 01:28