Conjure supports two different kinds of unions: tagged unions (also known as sum types or algebraic data types) and untagged unions (similar to C-style unions).
Tagged Unions (Sum Types) Proposed
Sum types, or tagged unions, allow you to define a type that can hold one of several different variants, each potentially with its own associated data. This is useful for representing data that can take on multiple forms while ensuring type safety.
To create a tagged union, just create a const value containing a set of types joined together using the pipe (|) operator.
struct Circle { radius f64 }
struct Rectangle { width f64, height f64 }
struct Triangle { base f64, height f64 }
const Shape = Circle | Rectangle | Triangle
var myShape Shape = Circle{ radius = 5.0 }Accessing Tagged Union Variants Proposed
You can use the is operator to check which variant of the union is currently held.
if myShape is Circle {
// `myShape` is treated as a `Circle` here
io.println("Circle with radius #{myShape.radius}")
} else if myShape is Rectangle {
// `myShape` is treated as a `Rectangle` here
io.println("Rectangle with width #{myShape.width} and height #{myShape.height}")
} else if myShape is Triangle {
// `myShape` is treated as a `Triangle` here
io.println("Triangle with base #{myShape.base} and height #{myShape.height}")
}Pattern-Matching Tagged Unions Proposed
You can then use pattern matching with the when expression/statement to handle each variant of the union.
when myShape {
case Circle:
// `myShape` is treated as a `Circle` here
io.println("Circle with radius #{myShape.radius}")
case Rectangle as rect:
// a new variable `rect` of type `Rectangle` is created
io.println("Rectangle with width #{rect.width} and height #{rect.height}")
case Triangle:
// `myShape` is treated as a `Triangle` here
io.println("Triangle with base #{myShape.base} and height #{myShape.height}")
}Untagged Unions
The alternative to tagged unions are untagged unions, which are similar to C-style unions. They allow you to define a type that can hold one of several different variants, but without any tagging or type safety. This means that you need to manage which variant is currently being used manually.
// A tagged union representing a block of data that can
// either be an integer, a float, or a struct.
union DataBlock {
int i32
float f64
point struct{ x f64, y f64 }
}
var block DataBlock
// Assign an integer to the union
block = i32(42)
// Read the integer from the union
var intValue = block.int
// Assign a float to the union
block = f64(3.14)