mir.algebraic — Algebraic Types
mir.algebraic provides type-safe discriminated unions for D — Variant, TaggedVariant, and Nullable — with exhaustive pattern matching, BetterC support, and zero-overhead access.
mir.algebraic is the Mir take on algebraic data types. It provides a Variant (anonymous tagged union) and TaggedVariant (named-tag variant) with compile-time exhaustiveness checking for match.
Basic Variant
import mir.algebraic;
// Declare a variant type
alias Shape = Variant!(int, double, string);
Shape s = 3.14;
// Exhaustive pattern match
s.match!(
(int i) => writefln!"int(%d)"(i),
(double d) => writefln!"double(%g)"(d),
(string t) => writefln!"string(%s)"(t),
);If you forget a case, the compiler tells you:
Error: none of the handlers in match handle type `string`Nullable — optional value
import mir.algebraic : Nullable;
Nullable!int opt = 42;
Nullable!int empty;
opt.match!(
(int v) => writeln("has value: ", v),
() => writeln("empty"),
);
// Or use get with default:
int val = opt.get(0); // 0 if emptyNullable!T is Variant!(T, typeof(null)) — no separate Option type needed.
TaggedVariant — named tags
import mir.algebraic;
struct Circle { double radius; }
struct Rect { double w, h; }
struct Triangle{ double base, height; }
alias Shape = TaggedVariant!(
["circle", Circle],
["rect", Rect],
["triangle", Triangle],
);
Shape s = Circle(5.0);
double area = s.match!(
(Circle c) => 3.14159 * c.radius * c.radius,
(Rect r) => r.w * r.h,
(Triangle t) => 0.5 * t.base * t.height,
);Peeking without full match
Shape s = Rect(3.0, 4.0);
if (auto rp = s.peek!Rect)
writeln("Rect area: ", rp.w * rp.h);
// Or trustedGet when you know the type:
Rect r = s.trustedGet!Rect;Algebraic — recursive / self-referential types
Algebraic is the building block for recursive variants (e.g. AST nodes):
import mir.algebraic : Algebraic, This;
// JSON-like value type
alias JSON = Algebraic!(
typeof(null),
bool,
long,
double,
string,
This[], // array of JSON (recursive)
This[string], // object (recursive)
);This is a placeholder for the variant type itself, enabling recursive definitions without pointer indirection.
match vs visit
match— exhaustive: compile error if any type is unhandledvisit— non-exhaustive: unhandled types hit anassert(0)at runtime
// visit: only handle some types
s.visit!(
(Circle c) => writeln("Circle"),
// Rect and Triangle fall through to assert(0)
);Equality and ordering
alias V = Variant!(int, double);
V a = 1, b = 1;
assert(a == b); // true
V c = 1.0;
assert(a != c); // different type tagComparison with other D sumtype libraries
| Feature | mir.algebraic | sumtype (Paul Backus) | std.variant |
|---|---|---|---|
| Exhaustive match | Yes | Yes | No |
| BetterC | Yes | Yes | No |
@nogc | Yes | Yes | No |
| Recursive types | Yes (This) | Limited | No |
| Named tags | Yes (TaggedVariant) | No | No |
| Nullable | Yes | Via Option!T | No |
mir-core
Base building blocks for the Mir ecosystem — algebraic types (sumtype / tagged union / variant), universal reflection API, and basic math primitives. BetterC and @nogc compatible.
mir-random
High-quality random number generation and statistical distributions for D. BetterC compatible, @nogc, with ndslice integration for filling arrays.