Alias std.variant.Algebraic
Algebraic data type restricted to a closed set of possible
types. It's an alias for VariantN
with an
appropriately-constructed maximum size. Algebraic
is
useful when it is desirable to restrict what a discriminated type
could hold to the end of defining simpler and more efficient
manipulation.
Example
auto v = Algebraic!(int, double, string)(5);
assert(v .peek!(int));
v = 3.14;
assert(v .peek!(double));
// auto x = v.peek!(long); // won't compile, type long not allowed
// v = '1'; // won't compile, type char not allowed
Example
Self-Referential Types
A useful and popular use of algebraic data structures is for defining self-referential data structures, i.e. structures that embed references to values of their own type within.
This is achieved with Algebraic
by using This
as a placeholder whenever a
reference to the type being defined is needed. The Algebraic
instantiation
will perform alpha renaming on its constituent types, replacing This
with the self-referenced type. The structure of the type involving This
may
be arbitrarily complex.
import std .typecons : Tuple, tuple;
// A tree is either a leaf or a branch of two other trees
alias Tree(Leaf) = Algebraic!(Leaf, Tuple!(This*, This*));
Tree!int tree = tuple(new Tree!int(42), new Tree!int(43));
Tree!int* right = tree .get!1[1];
writeln(*right); // 43
// An object is a double, a string, or a hash of objects
alias Obj = Algebraic!(double, string, This[string]);
Obj obj = "hello";
writeln(obj .get!1); // "hello"
obj = 42.0;
writeln(obj .get!0); // 42
obj = ["customer": Obj("John"), "paid": Obj(23.95)];
writeln(obj .get!2["customer"]); // "John"