Is multiple dispatch the same as function overloading?

As far as I understand, multiple dispatch means dynamic dispatch based on the types of several argument instead of just a single special argument.

Here is an example in C++:

#include <iostream>
#include <vector>

// abstract base class
class A {
public:
    virtual int foo(A* a) {
        return 1;
    }
};

// a concrete class with special behavior
class C1 : public A {
public:
    virtual int foo(A* a) {
        return 2;
    }
    virtual int foo(C1* a) {
        return 3;
    }
};

// a concrete class with default behavior
class C2 : public A {
};


int main() {
    std::vector<A*> v {new C1(), new C2()};
    for (auto e1: v) {
        for (auto e2: v) {
            std::cout << e1->foo(e2) << std::endl;
        }
    }
}

This prints

2
2
1
1

Here, only for the “first argument”, i.e., e1, the runtime type is taken into account while the type of the “second” argument is considered only at compile time.

In Julia, the method is chosen by the runtime types of all arguments. Therefore, we have the following behavior:

abstract A
foo(x::A, y::A) = 1

type C1 <: A end
foo(x::C1, y::A) = 2
foo(x::C1, y::C1) = 3

type C2 <: A end

function main()
    v = [C1(), C2()]
    for e1 in v
        for e2 in v
            println(foo(e1,e2))
        end
    end
end

main()

results in

3
2
1
1

Note the difference for the first method call, i.e., v[0]->foo(v[0]) vs. foo(v[1], v[1]).

4 Likes