Skip to content

Enumerations ​

Implementation status: simple enums / associated values / generic enums / switch exhaustiveness / if case are all Implemented; automatic Int raw values Partially implemented; indirect enum Not implemented

An enumeration defines a group of related values. SYX enums are Swift-style "algebraic data types (ADT)": each case may be a simple identifier or may carry associated values.

Simple Enumerations ​

swift
enum Status {
    case ok
    case err
    case pending
}

let s = Status.ok
print(s.tag)                              // 0 (internal tag)

The case keyword: SYX simple enums must write case (consistent with early Swift 1.x style; enum Status { ok, err, pending } is not legal).

Source: crates/syx-driver/tests/fixtures/lang/enum_associated.sy

Associated Values ​

swift
enum NetworkResult {
    case success(String)
    case failure(code: Int, message: String)
}

let r1 = NetworkResult.success("OK")
let r2 = NetworkResult.failure(code: 404, message: "Not Found")
  • Associated values may be named (code:, message:) or anonymous (positional)
  • One enum may have several case shapes (discriminated union)
  • The standard library Result<T, E> is defined in packages/core/builtins/result.sy

Source: crates/syx-driver/tests/fixtures/lang/enum_associated.sy

switch Matching ​

swift
func describe(_ r: NetworkResult) -> String {
    switch (r) {
    case .success(let data) {
        return "ok: \(data)"
    }
    case .failure(code: let c, message: let m) {
        return "fail code=\(c) msg=\(m)"
    }
    default {                              // An enum may omit default; an open domain needs one
        return "?"
    }
    }
}

Braces: a SYX case must be followed by a { } block. See Chapter 6, Control Flow.

Destructuring Named Associated Values ​

swift,errorL001
case .failure(code: let c, message: let m) { … }    // Named
case .failure(let c, let m) { … }                  // Positional
case let .success(data) { … }                       // Single-parameter shorthand

where Guards ​

swift,errorL001
case .success(let data) where (data.count > 0) { … }
case .failure(let m) where (m.hasPrefix("5")) { … }

See Chapter 6, Control Flow.

if case ​

swift
enum NetworkResult {
    case success(String)
    case failure(String)
}
let result = NetworkResult.success("ok")
if case .success(let data) = result {
    print(data)
} else {
    print("not success")
}

if case is a convenient single-branch form of switch. The patterns after case are the same as in a switch case.

Generic Enumerations ​

swift
enum Optional<T> {
    case some(T)
    case none
}

enum Result<T, E> {
    case ok(T)
    case err(E)
}
  • Generic parameters come after the enum name
  • Monomorphization generates concrete instances such as Optional<Int> / Optional<String>
  • The standard Optional and Result are pre-declared (you need not write them yourself)

Implemented (fixtures/lang/enum_associated.sy)

Nested Types ​

swift
enum Tree {
    case leaf(Int)
    case branch(left: Tree, right: Tree)
}

Recursive nesting: a single level of recursion compiles to an object reference; deep recursion needs indirect enum (Not implemented, planned). Wrap it in a class for now.

Raw Values (Partially Implemented) ​

swift
enum Direction: Int {
    case north = 0
    case east = 1
    case south = 2
    case west = 3
}
CapabilityStatus
: Int raw valuePartially implemented (Phase 50 basics)
: String raw valueNot implemented
Implicit raw valuesNot implemented (assignment must be explicit)

Alternative: a simple enum can use ordinary cases plus an explicit Int conversion. Full raw value support → later Phases.

Enum Methods ​

swift
enum Status {
    case ok, err, pending

    func isFinal() -> Bool {
        switch (self) {
        case .ok { return true }
        case .err { return true }
        case .pending { return false }
        }
    }

    func description() -> String {
        switch (self) {
        case .ok { return "ok" }
        case .err { return "err" }
        case .pending { return "..." }
        }
    }
}

print(Status.ok.isFinal())                 // true
print(Status.pending.description())        // "..."

self: inside an enum method, self is the current case (already bound to the case plus its associated values).

Enums and Protocols ​

Enums may adopt protocols (Equatable / Hashable / Codable and others):

swift
@Equatable
enum Status {
    case ok
    case err
    case pending
}

print(Status.ok == Status.err)            // false

Manual implementation: == for an associated-value enum is generated by the compiler from case + associated values (Implemented, Equatable synthesis).

For @Hashable / @Codable, see Chapter 19, Macros.

Codable L2 (Associated-Value Enums) ​

Since Phase 129, enums with associated values get encode / decode fully automatically (fingerprint macro-codable-l2:associated-enum-auto):

swift
@Codable
enum WireStatus {
    case ok(code: Int)
    case err(message: String)
}

func main() {
    let w = WireStatus.ok(code: 7)
    let text = w.encode()
    let back = WireStatus.decode(text: text)
}

Limits: the full set of generic associated values / arbitrary nesting / custom coding keys → later Phases.

Exhaustiveness ​

Enums and final class closed domains get automatic exhaustiveness checking in switch; incomplete case coverage → S007.

swift,errorS007
enum Color { case red, green, blue }

func describe(_ c: Color) -> String {
    switch (c) {
    case .red { return "red" }
    case .green { return "green" }
    case .blue { return "blue" }
    }                                       // ✅ Fully covered
}

func incomplete(_ c: Color) -> String {
    switch (c) {
    case .red { return "red" }
    }                                       // ❌ S007: missing cases
}

Choosing Between Enums and final class ​

NeedChoose
One shared case structure, pattern matchingenum
Methods with fields, or inheritanceclass / final class
Cross-process / deserializationenum (smaller, purer)
Associated values with named parametersenum case (case failure(code:, message:))
Variants need extra methods or a shared base classclass (polymorphic) or final class (closed)

Note: the lexer has no sealed keyword; use enum for ADTs and final class to forbid subclassing.

Complete Example ​

swift
import JSON

enum ApiResponse {
    case ok(data: String)
    case unauthorized
    case serverError(status: Int, body: String)
}

func handle(_ r: ApiResponse) -> String {
    switch (r) {
    case .ok(let data) where (data.count > 0) {
        return "OK: \(data)"
    }
    case .ok {
        return "OK (empty)"
    }
    case .unauthorized {
        return "401"
    }
    case .serverError(status: let s, body: let b) where (s >= 500) {
        return "5xx: \(b)"
    }
    case .serverError(status: let s, body: let b) {
        return "4xx[\(s)]: \(b)"
    }
    }
}

func main() {
    let r1 = ApiResponse.ok(data: "hello")
    let r2 = ApiResponse.serverError(status: 503, body: "down")
    print(handle(r1))                       // "OK: hello"
    print(handle(r2))                       // "5xx: down"
}

Diagnostics ​

CodeTriggerFix
S007Non-exhaustive switch (not all cases covered)Add the missing cases or a default
S010Associated-value destructuring mismatchCheck the enum definition
P001case missing its brace blockAdd { }

Differences from Swift ​

SwiftSYX
case ok, err (without the case keyword)Must write case ok / case err
Recursive indirect enumNot implemented (wrap in a class)
String / character raw valuesNot implemented (only Int, partially)
Default CustomStringConvertible implementationAn explicit func description() -> String is needed
@Codable associated-value enumsPartial GA (L2 fully automatic, Phase 129)
if case letif case .variant(let x) = expr (slightly different syntax)

Next chapter → Structures and Classes

See also → Language Reference: Declarations · Chapter 6, Control Flow · Chapter 19, Macros · Chapter 10, Structures and Classes

SYX · Apache-2.0