Conjure supports two different kinds of unions: data enums (tagged unions with associated data) and untagged unions (similar to C-style unions).
Data Enums (Tagged Unions)
Data enums allow you to define an enum where each variant can carry associated data. This is similar to Rust’s enums or algebraic data types. Each variant is tagged, so the compiler knows which variant is currently held.
// Define a data enum with variants that carry different data
enum Shape {
Circle f64 // radius
Rectangle { width f64, height f64 } // struct-style variant (planned)
Point // no associated data
}
// Construct variants using EnumType.Variant(value) syntax
var myShape = Shape.Circle(5.0)Pattern-Matching Data Enums
Use pattern matching with the when statement to handle each variant. The pattern syntax .Variant(binding) binds the associated data to a variable.
func describeShape(s Shape) string {
when s {
case .Circle(radius):
return "Circle with radius #{radius}"
case .Point:
return "A single point"
}
}Simple Example
// A common pattern: representing optional or result types
enum Result {
Ok i32
Err string
}
func divide(a i32, b i32) Result {
if b == 0 {
return Result.Err("division by zero")
}
return Result.Ok(a / b)
}
func main() {
var result = divide(10, 2)
when result {
case .Ok(value):
io.println("Result: #{value}")
case .Err(msg):
io.println("Error: #{msg}")
}
}Untagged Unions
The alternative to data enums 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.
// An untagged union for low-level data representation
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)