2.18. Variant¶
Variants are nameless types which provide 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 a 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.
Variants hold the index
of the current case, as well as the value for the current case only.
The current case selection can be checked via the is
operator, and accessed via the as
operator:
assert(t is i_value)
assert(t as i_value == 0x3f800000)
The entire variant selection can be modified by copying the properly constructed variant of a 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 a variant case of the incorrect type will cause a panic:
t = [[U_F i_value = 0x40000000]]
return t as f_value // panic, invalid variant index
Safe navigation is available via the ?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 an 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
The current index can be determined via the variant_index
function:
var t : U_F
assert(variant_index(t)==0)
The index value for a specific case can be determine via the variant_index
and safe_variant_index
type traits.
safe_variant_index
will return -1 for 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 the unsafe operation safe_variant_index
:
unsafe
set_variant_index(t, typeinfo(variant_index<f_value> t))
2.18.1. Alignment and data layout¶
Variants contain the ‘index’ of the current case, followed by a 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.
The variant type is aligned by the alignment of its largest case, but no less than that of an int32.