match

Applies a delegate or function to the given arguments depending on the held type, ensuring that all types are handled by the visiting functions.

The handler supports multiple dispatch or multimethods: a feature of handler in which a function or method can be dynamically dispatched based on the run time (dynamic) type or, in the more general case, some other attribute of more than one of its arguments.

Fuses algebraic types on return.

alias match(visitors...) = visitImpl!(naryFun!visitors, Exhaustive.compileTime, true)

Examples

struct Asteroid { uint size; }
struct Spaceship { uint size; }
alias SpaceObject = Variant!(Asteroid, Spaceship);

alias collideWith = match!(
    (Asteroid x, Asteroid y) => "a/a",
    (Asteroid x, Spaceship y) => "a/s",
    (Spaceship x, Asteroid y) => "s/a",
    (Spaceship x, Spaceship y) => "s/s",
);

import mir.utility: min;

// Direct access of a member in case of all algebraic types has this member
alias oops = (a, b) => (a.size + b.size) > 3 && min(a.size, b.size) > 1;

alias collide = (x, y) => oops(x, y) ? "big-boom" : collideWith(x, y);

auto ea = Asteroid(1);
auto es = Spaceship(2);
auto oa = SpaceObject(ea);
auto os = SpaceObject(es);

// Asteroid-Asteroid
assert(collide(ea, ea) == "a/a");
assert(collide(ea, oa) == "a/a");
assert(collide(oa, ea) == "a/a");
assert(collide(oa, oa) == "a/a");

// Asteroid-Spaceship
assert(collide(ea, es) == "a/s");
assert(collide(ea, os) == "a/s");
assert(collide(oa, es) == "a/s");
assert(collide(oa, os) == "a/s");

// Spaceship-Asteroid
assert(collide(es, ea) == "s/a");
assert(collide(es, oa) == "s/a");
assert(collide(os, ea) == "s/a");
assert(collide(os, oa) == "s/a");

// Spaceship-Spaceship
assert(collide(es, es) == "big-boom");
assert(collide(es, os) == "big-boom");
assert(collide(os, es) == "big-boom");
assert(collide(os, os) == "big-boom");

See Also

Meta