Skip to main content

Tag: design pattern

Multiple Dispatch in C++

A great feature that can be used in more dynamic languages is multiple dispatch. Here’s an example in Julia taken from the Wikipedia article.

abstract type SpaceObject end

struct Asteroid <: SpaceObject
    # Asteroid fields
end
struct Spaceship <: SpaceObject
    # Spaceship fields
end

collide_with(::Asteroid, ::Spaceship) = # Asteroid/Spaceship collision
collide_with(::Spaceship, ::Asteroid) = # Spaceship/Asteroid collision
collide_with(::Spaceship, ::Spaceship) = # Spaceship/Spaceship collision
collide_with(::Asteroid, ::Asteroid) = # Asteroid/Asteroid collision

collide(x::SpaceObject, y::SpaceObject) = collide_with(x, y)

The collide function calls collide_with which, at runtime, will inspect the types of its arguments and dispatch to the appropriate implementation.

Julia was created with multiple dispatch as a first-class citizen, it is used liberally in its ecosystem. C++ does not have access to such a feature natively, but there are alternatives that I will be presenting in this article, and try to justify there uses and limitations.

Magic Conversions in C++

One feature that I like a lot in Rust is return type polymorphism, best exemplified with the following snippet of code:

use std::collections::HashSet;

fn main() {
    let vec: Vec<_> = (0..10).filter(|a| a % 2 == 0).collect();
    let set: HashSet<_> = (0..10).filter(|a| a % 2 == 0).collect();
    println!("vec: {:?}", vec);
    println!("set: {:?}", set); 
}

We have the same expression ((0..10).filter(|a| a % 2 == 0).collect()) that results in two totally different types of values (a Vec and a HashSet)!

This is because Rust allows you to write a function which is generic in its return type, which is a super-power that C++ does not have. But is there a way to emulate this behaviour with some clever code?