ajhahn.de
← all chapters

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
    }
}