std.variant

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.

A Variant object can hold a value of any type, with very few restrictions (such as shared types and noncopyable types). Setting the value is as immediate as assigning to the Variant object. To read back the value of the appropriate type T, use the get method. To query whether a Variant currently holds a value of type T, use peek. To fetch the exact type currently held, call type, which returns the TypeInfo of the current value.

In addition to Variant, this module also defines the Algebraic type constructor. Unlike Variant, Algebraic only allows a finite set of types, which are specified in the instantiation (e.g. Algebraic!(int, string) may only hold an int or a string).

Warning: Algebraic is outdated and not recommended for use in new

code. Instead, use SumType.

Credits: Reviewed by Brad Roberts. Daniel Keep provided a detailed code review prompting the following improvements: (1) better support for arrays; (2) support for associative arrays; (3) friendlier behavior towards the garbage collector.

Types 6

structThis
private aliasThis2Variant(V, T...) = AliasSeq!(ReplaceTypeUnless!(isAlgebraic, This, V, T))
structVariantN(size_t maxDataSize, AllowedTypesParam...)

Back-end type seldom used directly by user code. Two commonly-used types using VariantN are:

  1. Algebraic: A closed discriminated union with a

    limited type universe (e.g., Algebraic!(int, double, string) only accepts these three types and rejects anything else).

  2. Variant: An open discriminated union allowing an unbounded set of types. If any of the types in the Variant are larger than the largest built-in type, they will automatically be boxed. This means that even large types will only be the size of a pointer within the Variant, but this also implies some overhead. Variant can accommodate all primitive types and all user-defined types.

Both Algebraic and Variant share VariantN's interface. (See their respective documentations below.)

VariantN is a discriminated union type parameterized with the largest size of the types stored (maxDataSize) and with the list of allowed types (AllowedTypes). If the list is empty, then any type up of size up to maxDataSize (rounded up for alignment) can be stored in a VariantN object without being boxed (types larger than this will be boxed).

Fields
SizeChecker.sizeof - (int function()).sizeof size
ptrdiff_t function(OpID selector, ubyte[size] * store, void * data) fptr
Methods
ptrdiff_t handler(A : void)(OpID selector, ubyte[size] *, void * parm)
ptrdiff_t handler(A)(OpID selector, ubyte[size] * pStore, void * parm)
VariantN opAssign(T)(T rhs)Assigns a `VariantN` from a generic argument. Statically rejects disallowed types.
VariantN opAssign(T : VariantN!(tsize, Types), size_t tsize, Types...)(T rhs) if (!is(T : VariantN) && Types.length > 0 && allSatisfy!(allowed, Types))
Variant opCall(P...)(auto ref P params)
bool hasValue() @property const pure nothrowReturns true if and only if the `VariantN` object holds a valid value (has been initialized with, or assigned from, a valid value).
inout(T) * peek(T)() @property inoutIf 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.
TypeInfo type() @property const nothrow @trustedReturns the `typeid` of the currently held value.
bool convertsTo(T)() @property constReturns `true` if and only if the `VariantN` object holds an object implicitly convertible to type `T`. Implicit convertibility is defined as per AllImplicitConversionTargets.
inout(T) get(T)() @property inoutReturns the value stored in the `VariantN` object, either by specifying the needed type or the index in the list of allowed types. The latter overload only applies to bounded variants (e.g. Algebra...
@property auto get(uint index)() if (index < AllowedTypes.length) inoutDitto
T coerce(T)() @propertyReturns 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 toString()Formats the stored value as a string.
bool opEquals(T)(auto ref T rhs) if (allowed!T || is(immutable T == immutable VariantN)) constComparison for equality used by the "==" and "!=" operators.
int opCmp(ref const VariantN rhs) const
int opCmp(T)(T rhs) if (allowed!T)Ordering comparison used by the "<", "<=", ">", and ">=" operators. In case comparison is not sensible between the held value and `rhs`, an exception is thrown.
size_t toHash() const nothrow @safeComputes the hash of the held value.
private VariantN opArithmetic(T, string op)(T other)
private VariantN opLogic(T, string op)(T other)
VariantN opBinary(string op, T)(T rhs) if ((op == "+" || op == "-" || op == "*" || op == "/" || op == "^^" || op == "%") && is(typeof(opArithmetic!(T, op)(rhs))))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 b...
VariantN opBinary(string op, T)(T rhs) if ((op == "&" || op == "|" || op == "^" || op == ">>" || op == "<<" || op == ">>>") && is(typeof(opLogic!(T, op)(rhs))))ditto
VariantN opBinaryRight(string op, T)(T lhs) if ((op == "+" || op == "*") && is(typeof(opArithmetic!(T, op)(lhs))))ditto
VariantN opBinaryRight(string op, T)(T lhs) if ((op == "&" || op == "|" || op == "^") && is(typeof(opLogic!(T, op)(lhs))))ditto
VariantN opBinary(string op, T)(T rhs) if (op == "~")ditto
VariantN opOpAssign(string op, T)(T rhs)ditto
inout(Variant) opIndex(K)(K i) inoutArray and associative array operations. If a VariantN contains an (associative) array, it can be indexed into. Otherwise, an exception is thrown.
Variant opIndexAssign(T, N)(T value, N i)ditto
Variant opIndexOpAssign(string op, T, N)(T value, N i)ditto
size_t length() @propertyIf the `VariantN` contains an (associative) array, returns the length of that array. Otherwise, throws an exception.
int opApply(Delegate)(scope Delegate dg) if (is(Delegate == delegate))If the `VariantN` contains an array, applies `dg` to each element of the array in turn. Otherwise, throws an exception.
Constructors
this(T value)Constructs a `VariantN` value given an argument of a generic type. Statically rejects disallowed types.
this(T value)Allows assignment from a subset algebraic type
Nested Templates
SizeChecker
allowed(T)Tells whether a type `T` is statically allowed for storage inside a `VariantN` object by looking `T` up in `AllowedTypes`.
OpID
private structFakeComplexReal
Fields
real re
aliasVariant = VariantN!(maxSize!(FakeComplexReal, char[], void delegate()))

Alias for VariantN instantiated with the largest size of creal, char[], and void delegate(). This ensures that Variant is large enough to hold all of D's predefined types unboxed, 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 unboxed, or for saving memory.

classVariantException : Exception

Thrown in three cases:

  1. An uninitialized Variant is used in any way except

    assignment and hasValue;

  2. A get or coerce is attempted with an incompatible target type;
  3. A comparison between Variant objects of

    incompatible types is attempted.

Fields
TypeInfo sourceThe source type in the conversion or comparison
TypeInfo targetThe target type in the conversion or comparison
Constructors
this(string s)
this(TypeInfo source, TypeInfo target)

Functions 2

fnVariant[] variantArray(T...)(T args)Returns an array of variants constructed from `args`.
private fnauto visitImpl(bool Strict, VariantType, Handler...)(VariantType variant) if (isAlgebraic!VariantType && Handler.length > 0)

Templates 6

tmplmaxSize(Ts...)

Gives the sizeof the largest type given.

See Also

tmplmaxVariantAlignment(U...) if (isTypeTuple!U)
tmplAlgebraic(T...)

_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.

Warning: Algebraic is outdated and not recommended for use in new

code. Instead, use SumType.

tmplvisit(Handlers...) if (Handlers.length > 0)

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 variant's current value. Visiting handlers are passed in the template parameter list. It is statically ensured that all held types of variant are handled across all handlers. visit allows delegates and static functions to be passed as parameters.

If a function with an untyped parameter is specified, this function is called when the variant contains a type that does not match any other function. This can be used to apply the same function across multiple possible types. Exactly one generic function is allowed.

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.

Returns

The return type of visit is deduced from the visiting functions and must be

the same across all overloads.

Throws

VariantException if variant doesn't hold a value and no

parameter-less fallback function is specified.

Functions
auto visit(VariantType)(VariantType variant) if (isAlgebraic!VariantType)
tmpltryVisit(Handlers...) if (Handlers.length > 0)

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.

Returns

The return type of tryVisit is deduced from the visiting functions and must be

the same across all overloads.

Throws

VariantException if variant doesn't hold a value or

variant holds a value which isn't handled by the visiting functions, when no parameter-less fallback function is specified.

Functions
auto tryVisit(VariantType)(VariantType variant) if (isAlgebraic!VariantType)
tmplisAlgebraic(Type)