Unions
A Union in Cyrus is a composite data type similar to C-style unions. It allows multiple fields to share the same memory location, so only one of its fields can hold a valid value at any given time.
Unlike structs, writing to one field will overwrite the memory for all others.
Unions Are Not Memory-Safe
Unions in Cyrus are not memory-safe. Reading a field that was not most recently written is undefined behavior, just like in C. Use unions only when you explicitly need memory-efficient, low-level data representations.
Safe Alternative
If you want a memory-safe way to store different types of values, use an enum, which enforces at compile time which variant is active.
Defining a Union
union DataUnion {
a: int;
b: float64;
}
fn main() {
var un = DataUnion;
un.b = 3.14;
}
Using a Union
You can create a union instance and assign fields directly:
fn main() {
var un = DataUnion;
un.a = 42; // set the integer field
un.b = 3.14; // overwrites the same memory with a float
}
After un.b = 3.14, the value of un.a is no longer valid.
Union Initialization
Unions can be initialized using a Union Initializer, specifying which field to set at creation:
var un: DataUnion = DataUnion { a: 10 };
Rules:
- Only one field should be initialized.
- The union's memory will be set according to that field.
Practical Use Cases
Unions are low-level tools, mainly used in systems programming:
- Type punning: reinterpret the same memory as different types.
- Interfacing with C libraries: many C APIs expose unions in their structs.
- Memory efficiency: when you know only one of several large fields will be used at once.
Example: Interpreting the same 32-bit data as either an integer or raw bytes.
import std::libc{printf};
union IntBytes {
value: int;
bytes: uint8[4];
}
fn main() {
var data = IntBytes { value: 0x12345678 };
printf("%x %x %x %x\n", data.bytes[0], data.bytes[1], data.bytes[2], data.bytes[3]);
}
Output (on little-endian systems):
78 56 34 12

