2.17. Variant

Variant is a nameless type which provides support for values that can be one of a number of named cases, possibly each with different values and types:

var t : variant<i_value:uint;f_value:float>

There is shorthand type alias syntax to define a variant:

variant U_F
    i_value : uint
    f_value : float

typedef
    U_F = variant<i_value:uint;f_value:float> // exactly the same as the declaration above

Any two variants are the same type, if they have the same named cases of the same types in the same order.

Variant holds index of current case, as well as value for the current case only.

Current case selection can be checked via is operator, and accessed via as operator:

assert(t is i_value)
assert(t as i_value == 0x3f800000)

Entire variant selection can be modified by copying properly constructed variant of different case:

t = [[U_F i_value = 0x40000000]]    // now case is i_value
t = [[U_F f_value = 1.0]]           // now case is f_value

Accessing variant case of incorrect type will cause panic:

t = [[U_F i_value = 0x40000000]]
return t as f_value                 // panic, invalid variant index

Safe navigation is available via ?as operation:

return t ?as f_value ?? 1.0         // will return 1.0 if t is not f_value

Cases can also be accessed in unsafe manner without checking the type:

unsafe
    t.i_value = 0x3f800000
    return t.f_value                    // will return memory, occupied by f_value - i.e. 1.0f

Current index can be determined via variant_index function:

var t : U_F
assert(variant_index(t)==0)

Index value for specific case can be determine via variant_index and safe_variant_index type traits. safe_variant_index will return -1 for the invalid indices and types, whereas variant_index will report a compilation error:

assert(typeinfo(variant_index<i_value> t)==0)
assert(typeinfo(variant_index<f_value> t)==1)
assert(typeinfo(variant_index<unknown_value> t)==-1) // compilation error

assert(typeinfo(safe_variant_index<i_value> t)==0)
assert(typeinfo(safe_variant_index<f_value> t)==1)
assert(typeinfo(safe_variant_index<unknown_value> t)==-1)

Current case selection can be modified with unsafe operation safe_variant_index:

unsafe
    set_variant_index(t, typeinfo(variant_index<f_value> t))

2.17.1. Alignment and data layout

Variant contains ‘index’ of the current case, followed by union of individual cases, similar to the following C++ layout:

struct MyVariantName {
    int32_t __variant_index;
    union {
        type0   case0;
        type1   case1;
        ...
    };
};

Individual cases start from the same offset.

Variant type is aligned by alignment of its largest case, but no less than that of int32.