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");
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.