# Chapter 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. ```flash 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**: ```flash // 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. ```flash 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)`: ```flash const Status = enum(u8) { ok, pending, failed, } ``` ### Explicit Discriminants You can assign explicit integer values to enum variants using the `=` operator: ```flash 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`. ```flash 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). ```flash 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: ```flash 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**. ```flash const Status = enum(u8) { ok, pending, failed, pub const initial = Status.pending pub fn isDone(self Status) bool { return self == .ok || self == .failed } } ```