D Programming Language 2.0

- Comments
- D
- Search
- Home

Last update Wed Jul 9 01:24:50 2008

# 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.
Synopsis:

     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

Author:
Andrei Alexandrescu
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.

struct VariantN(size_t maxDataSize,AllowedTypes...);
  VariantN is a back-end type seldom used directly by user code. Two commonly-used types using VariantN as back-end 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. The restriction is that the size of the stored type cannot be larger than the largest built-in type. This means that Variant can accommodate all primitive types and all user-defined types except for large structs.
  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.
  template allowed(T)
    Tells whether a type T is statically allowed for storage inside a VariantN object by looking T up in AllowedTypes. If AllowedTypes is empty, all types of size up to maxSize are allowed.
  template opCall(T)
    Constructs a VariantN value given an argument of a generic type. Statically rejects disallowed types.
  template opAssign(T)
    Assigns a VariantN from a generic argument. Statically rejects disallowed types.
    VariantN opAssign(T rhs);
      Assigns a VariantN from a generic argument. Statically rejects disallowed types.
  bool hasValue();
    Returns true if and only if the VariantN object holds a valid value (has been initialized with, or assigned from, a valid value).
    Example:

         Variant a;
         assert(!a.hasValue);
         Variant b;
         a = b;
         assert(!a.hasValue); // still no value
         a = 5;
         assert(a.hasValue);

  template peek(T)
    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.
    Example:

         Variant a = 5;
         auto b = a.peek!(int);
         assert(b !is null);
         *b = 6;
         assert(a == 6);

    T* peek();
      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.
      Example:

           Variant a = 5;
           auto b = a.peek!(int);
           assert(b !is null);
           *b = 6;
           assert(a == 6);

  TypeInfo type();
    Returns the typeid of the currently held value.
  template convertsTo(T)
    Returns true if and only if the VariantN object holds an object implicitly convertible to type U. Implicit convertibility is defined as per ImplicitConversionTargets.
    bool convertsTo();
      Returns true if and only if the VariantN object holds an object implicitly convertible to type U. Implicit convertibility is defined as per ImplicitConversionTargets.
  template DecayStaticToDynamicArray(T)
    A workaround for the fact that functions cannot return statically-sized arrays by value. Essentially DecayStaticToDynamicArray!(T[N]) is an alias for T[] and DecayStaticToDynamicArray!(T) is an alias for T.
  template get(T)
    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.
    DecayStaticToDynamicArray!(T) get();
      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.
  template coerce(T)
    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.
    T coerce();
      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.
  string toString();
    Formats the stored value as a string.
  template opEquals(T)
    Comparison for equality used by the "==" and "!=" operators.
    bool opEquals(T rhs);
      Comparison for equality used by the "==" and "!=" operators.
  template opCmp(T)
    Ordering comparison used by the "<", "<=", ">", and ">=" operators. In case comparison is not sensible between the held value and rhs, an exception is thrown.
    int opCmp(T rhs);
      Ordering comparison used by the "<", "<=", ">", and ">=" operators. In case comparison is not sensible between the held value and rhs, an exception is thrown.
  uint toHash();
    Computes the hash of the held value.
  template opAdd(T)
  template opSub(T)
    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.
    VariantN opAdd(T 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 built-in rules for arithmetic conversions.
  template opMul(T)
  template opDiv(T)
  template opMod(T)
  template opAnd(T)
  template opOr(T)
  template opXor(T)
  template opShl(T)
  template opShr(T)
  template opUShr(T)
  template opCat(T)
  template opAddAssign(T)
  template opSubAssign(T)
  template opMulAssign(T)
  template opDivAssign(T)
  template opModAssign(T)
  template opAndAssign(T)
  template opOrAssign(T)
  template opXorAssign(T)
  template opShlAssign(T)
  template opShrAssign(T)
  template opUShrAssign(T)
  template opCatAssign(T)
    ditto
    ditto
    VariantN opMul(T rhs);
      ditto
      ditto
  template opIndex(K)
  template opIndexAssign(T,N)
    Array and associative array operations. If a VariantN contains an (associative) array, it can be indexed into. Otherwise, an exception is thrown.
    Example:

         auto a = Variant(new int[10]);
         a[5] = 42;
         assert(a[5] == 42);
         int[int] hash = [ 42:24 ];
         a = hash;
         assert(a[42] == 24);

    Caveat:
    Due to limitations in current language, read-modify-write operations op= will not work properly:

         Variant a = new int[10];
         a[5] = 42;
         a[5] += 8;
         assert(a[5] == 50); // fails, a[5] is still 42

    VariantN opIndex(K i);
      Array and associative array operations. If a VariantN contains an (associative) array, it can be indexed into. Otherwise, an exception is thrown.
      Example:

           auto a = Variant(new int[10]);
           a[5] = 42;
           assert(a[5] == 42);
           int[int] hash = [ 42:24 ];
           a = hash;
           assert(a[42] == 24);

      Caveat:
      Due to limitations in current language, read-modify-write operations op= will not work properly:

           Variant a = new int[10];
           a[5] = 42;
           a[5] += 8;
           assert(a[5] == 50); // fails, a[5] is still 42

  size_t length();
    If the VariantN contains an (associative) array, returns the length of that array. Otherwise, throws an exception.
template Algebraic(T...)
  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.
  BUGS:
  Currently, Algebraic does not allow recursive data types. They will be allowed in a future iteration of the implementation.
  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

alias Variant;
  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.
Variant[] variantArray(T...)(T args);
  Returns an array of variants constructed from args.
  Example:

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

  Code that needs functionality similar to the boxArray function in the std.boxer module can achieve it like this:

       // old
       Box[] fun(...)
       {
           ...
           return boxArray(_arguments, _argptr);
       }
       // new
       Variant[] fun(T...)(T args)
       {
           ...
           return variantArray(args);
       }

  This is by design. During construction the Variant needs static type information about the type being held, so as to store a pointer to function for fast retrieval.
class VariantException: object.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.
  TypeInfo source;
    The source type in the conversion or comparison
  TypeInfo target;
    The target type in the conversion or comparison

Copyright © 1999-2008 by Digital Mars, All Rights Reserved | Page generated by Ddoc.