Flash tutorial · 6 / 12
6. Structs, Enums & Unions
Flash provides powerful composite type systems: structs for group data, enums for labeled choices, and tagged unions for dynamic variants.
1. Structs
Structs group multiple related variables (fields) into a single type.
Defining a Struct
In Flash, struct fields are defined as name type (without a colon or comma). A struct can also carry associated functions (methods) and constants.
const Point = struct {
x i32,
y i32,
// An associated constant
pub const origin = Point{ .x = 0, .y = 0 }
// A method taking a pointer receiver
pub fn distanceSquared(self *Point, other *Point) i32 {
dx := self.x - other.x
dy := self.y - other.y
return (dx * dx) + (dy * dy)
}
}
Instantiating Structs
Flash supports both anonymous struct literals (.{}) and typed struct literals:
// Anonymous literal (type inferred from context)
var p1 Point = .{ .x = 10, .y = 20 }
// Typed literal
p2 := Point{ .x = -5, .y = 12 }
// Empty struct literal (all fields undefined / default)
var p3 Point = .{}
Layout Modifiers (packed struct / extern struct)
By default the compiler is free to order and pad struct fields. Two modifiers pin the layout, prefixing the keyword:
packed struct— the fields pack bit-exactly, in order, with no padding. The shape for an on-disk format whose byte offsets must never move.extern struct— the fields are laid out by the C ABI, for a type that crosses an ABI boundary and must look identical on both sides.
const DiskHeader = packed struct {
magic u32,
flags u8,
count u8,
}
Field defaults and associated declarations work unchanged under either layout. Two boundaries: the backing-integer form packed struct(uN) is not part of the grammar — the field widths define the layout — and the modifiers apply to structs only (packed union and extern enum are rejected).
2. Enums
Enums define a set of named, integer-backed constant values.
Basic Enums & Backing Types
You can define an enum with an optional backing integer type using enum(T):
const Status = enum(u8) {
ok,
pending,
failed,
}
Explicit Discriminants
You can assign explicit integer values to enum variants using the = operator:
const ErrorCode = enum(u32) {
success = 0,
permission_denied = 1,
out_of_memory = 12,
io_error = 1 << 3, // bit-shift discriminants are supported!
}
Inferred Enum Literals
When the expected type of an enum is known by the compiler, you can write .variant instead of EnumName.variant.
var state Status = .pending
fn check(s Status) bool {
return s == .ok
}
3. Tagged Unions
Tagged unions store one value at a time out of several possible types. They carry an active "tag" that identifies which field is currently stored.
Defining a Tagged Union
In Flash, you define a tagged union using the union(enum) syntax. Fields can carry payload types, or be empty (void).
const PayloadValue = union(enum) {
integer i32,
float f32,
text cstr,
none, // void variant
}
Instantiating Unions
Create a union instance by specifying the active variant and its value:
var val = PayloadValue{ .integer = 42 }
var empty = PayloadValue{ .none = .{} } // Void payload
4. Methods & Constants in Enums and Unions
The associated declarations a struct body carries — fn methods, const constants, and use imports — are accepted inside enum and union bodies too, under the same layout rule: variants first, then the declarations.
const Status = enum(u8) {
ok,
pending,
failed,
pub const initial = Status.pending
pub fn isDone(self Status) bool {
return self == .ok || self == .failed
}
}