This module implements a discriminated union type (a.k.a. tagged union, algebraic type). Such types are useful for type-uniform binary interfaces, interfacing with scripting languages, and comfortable exploratory programming.
Variant a; // Must assign before use, otherwise exception ensues // Initialize with an integer; make the type int Variant b = 42; assert(b.type == typeid(int)); // Peek at the value assert(b.peek!(int) !is null && *b.peek!(int) == 42); // Automatically convert per language rules auto x = b.get!(real); // Assign any other type, including other variants a = b; a = 3.14; assert(a.type == typeid(double)); // Implicit conversions work just as with built-in types assert(a < b); // Check for convertibility assert(!a.convertsTo!(int)); // double not convertible to int // Strings and all other arrays are supported a = "now I'm a string"; assert(a == "now I'm a string"); a = new int[42]; // can also assign arrays assert(a.length == 42); a[5] = 7; assert(a[5] == 7); // Can also assign class values class Foo {} auto foo = new Foo; a = foo; assert(*a.peek!(Foo) == foo); // and full type information is preserved
Gives the sizeof the largest type given.
VariantN is a back-end type seldom used directly by user code. Two commonly-used types using VariantN as back-end are:
Constructs a VariantN value given an argument of a generic type. Statically rejects disallowed types.
Assigns a VariantN from a generic argument. Statically rejects disallowed types.
Returns true if and only if the VariantN object holds a valid value (has been initialized with, or assigned from, a valid value).
Variant a; assert(!a.hasValue); Variant b; a = b; assert(!a.hasValue); // still no value a = 5; assert(a.hasValue);
If the VariantN object holds a value of the exact type T, returns a pointer to that value. Otherwise, returns null. In cases where T is statically disallowed, peek will not compile.
Variant a = 5; auto b = a.peek!(int); assert(b !is null); *b = 6; assert(a == 6);
Returns the typeid of the currently held value.
Returns true if and only if the VariantN object holds an object implicitly convertible to type U. Implicit convertibility is defined as per ImplicitConversionTargets.
Returns the value stored in the VariantN object, implicitly converted to the requested type T, in fact DecayStaticToDynamicArray!(T). If an implicit conversion is not possible, throws a VariantException.
Returns the value stored in the VariantN object, explicitly converted (coerced) to the requested type T. If T is a string type, the value is formatted as a string. If the VariantN object is a string, a parse of the string to type T is attempted. If a conversion is not possible, throws a VariantException.
Formats the stored value as a string.
Comparison for equality used by the "==" and "!=" operators.
Ordering comparison used by the "<", "<=", ">", and ">=" operators. In case comparison is not sensible between the held value and rhs, an exception is thrown.
Computes the hash of the held value.
Arithmetic between VariantN objects and numeric values. All arithmetic operations return a VariantN object typed depending on the types of both values involved. The conversion rules mimic D's built-in rules for arithmetic conversions.
Array and associative array operations. If a VariantN contains an (associative) array, it can be indexed into. Otherwise, an exception is thrown.
auto a = Variant(new int[10]); a[5] = 42; assert(a[5] == 42); int[int] hash = [ 42:24 ]; a = hash; assert(a[42] == 24);
Variant a = new int[10]; a[5] = 42; a[5] += 8; assert(a[5] == 50); // fails, a[5] is still 42
If the VariantN contains an (associative) array, returns the length of that array. Otherwise, throws an exception.
If the VariantN contains an array, applies dg to each element of the array in turn. Otherwise, throws an exception.
Algebraic data type restricted to a closed set of possible types. It's an alias for a 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.
Future additions to Algebraic will allow compile-time checking that all possible types are handled by user code, eliminating a large class of errors.
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
Variant is an alias for VariantN instantiated with the largest of creal, char[], and void delegate(). This ensures that Variant is large enough to hold all of D's predefined types, including all numeric types, pointers, delegates, and class references. You may want to use VariantN directly with a different maximum size either for storing larger types, or for saving memory.
Returns an array of variants constructed from args.
auto a = variantArray(1, 3.14, "Hi!"); assert(a[1] == 3.14); auto b = Variant(a); // variant array as variant assert(b[1] == 3.14);
// old Box[] fun(...) { ... return boxArray(_arguments, _argptr); } // new Variant[] fun(T...)(T args) { ... return variantArray(args); }
Thrown in three cases:
Applies a delegate or function to the given Algebraic depending on the held type, ensuring that all types are handled by the visiting functions.
The delegate or function having the currently held value as parameter is called
with 's current value. Visiting handlers are passed
in the template parameter list.
It is statically ensured that all types of
variant are handled accross all handlers.
visit allows delegates and static functions to be passed
as parameters.
If a function without parameters is specified, this function is called
when variant doesn't hold a value. Exactly one parameter-less function
is allowed.
Duplicate overloads matching the same type in one of the visitors are disallowed.
Algebraic!(int, string) variant; variant = 10; assert(variant.visit!((string s) => cast(int)s.length, (int i) => i)() == 10); variant = "string"; assert(variant.visit!((int i) => return i, (string s) => cast(int)s.length)() == 6); // Error function usage Algebraic!(int, string) emptyVar; assert(variant.visit!((string s) => cast(int)s.length, (int i) => i, () => -1)() == -1);
Behaves as visit but doesn't enforce that all types are handled by the visiting functions.
If a parameter-less function is specified it is called when either variant doesn't hold a value or holds a type which isn't handled by the visiting functions.
Algebraic!(int, string) variant; variant = 10; auto which = -1; variant.tryVisit!((int i) { which = 0; })(); assert(which = 0); // Error function usage variant = "test"; variant.tryVisit!((int i) { which = 0; }, () { which = -100; })(); assert(which == -100);