Conjure supports union types, which are types that can hold one of several variants. Each variant can optionally have an associated payload type. Unions are useful for representing data that can take on multiple forms.
Unions in Conjure are discriminated by default. This means each variant has a tag identifying which variant it is, allowing for safe and efficient pattern matching.
Defining Unions
Unions are defined using the union keyword, followed by the union name and a body containing the variants. Each variant can optionally have a payload type. When a variant does not have a payload, it operates similarly to an enum variant.
The default value for a union is the first variant listed. If the first variant has a payload, it will be initialized with the default value of that payload type.
union MyUnion {
A // variant A with no payload
B i32 // variant B with an i32 payload
C f64 // variant C with an f64 payload
D { x: i32, y: i32 } // variant D with a struct payload
}
var myUnion MyUnion
myUnion = MyUnion.A // sets myUnion to variant A
myUnion = MyUnion.B(42) // sets myUnion to variant B with payload 42
myUnion = MyUnion.C(3.14) // sets myUnion to variant C with payload 3.14
myUnion = MyUnion.D{ x: 10, y: 20 } // sets myUnion to variant D with struct payloadUsing Unions
You can use pattern matching to handle different variants of a union. The when expression/statement allows you to match against each variant and access its payload if it has one.
It’s important to point out that when expressions must be exhaustive, meaning you must handle every possible variant of the union or provide a fallback with else. If you do not, the compiler will raise an error.
when myUnion {
MyUnion.A {
// handle variant A
}
MyUnion.B(value) {
// handle variant B, with payload 'value'
}
MyUnion.C(value) {
// handle variant C, with payload 'value'
}
MyUnion.D{ x, y } {
// handle variant D, with struct payload destructured into x and y
}
}Annotations Proposed
@untagged
There may be times where you want/need to manage tagging yourself and have the union simply occupy the space of its largest variant (like in C). You can do this by annotating the union with @untagged.
When using @untagged, you must provide a payload for every variant in the union. If you do not, the compiler will raise an error.
@untagged union MyUnion {
A i32
B f64
C // error: variant 'C' must have a payload in an untagged union
}