1. Pattern Matching

8. Pattern Matching #

8.1 Basic Patterns #

let result = match value {
    0 => "zero"
    1 => "one"
    n => "other: " + toString(n)
}

8.2 Union Type Patterns #

type Option = Some { value: Int } | None

let message = match option {
    Some x => "Value: " + toString(x.value)
    None => "No value"
}

8.3 Wildcard Patterns #

The underscore _ matches any value:

let category = match score {
    100 => "perfect"
    90 => "excellent" 
    _ => "good"
}

8.4 Type Annotation Patterns #

Type annotation patterns use the : operator to match values of specific types. This is REQUIRED for any types.

type_pattern := ID ':' type
structural_pattern := ID ':' '{' field_list '}'
anonymous_structural_pattern := '{' field_list '}'
constructor_pattern := ID ('(' pattern (',' pattern)* ')')?
variable_pattern := ID
wildcard_pattern := '_'

Examples:

// Required for any types
match anyValue {
    num: Int => num + 1
    text: String => length(text)
    flag: Bool => if flag then 1 else 0
    _ => 0
}

// Structural matching - matches any type with these fields
match anyValue {
    { name, age } => print("${name}: ${age}")           // Anonymous structural
    p: { name, age } => print("Person ${p.name}: ${p.age}")  // Named structural
    u: User { id } => print("User ${id}")               // Traditional typed
    _ => print("Unknown")
}

// Advanced structural patterns
match anyValue {
    { x, y } => print("Point: (${x}, ${y})")           // Any type with x, y fields
    p: { name } => print("Named thing: ${p.name}")     // Any type with name field
    { id, email, active: Bool } => print("Active user: ${id}")  // Mixed field patterns
    _ => print("No match")
}

// Type patterns with field destructuring
match result {
    success: Success { value, timestamp } => processSuccess(value, timestamp)
    error: Error { code, message } => handleError(code, message)
    _ => defaultHandler()
}

Pattern Matching Features #

1. Type Annotation Patterns #

match anyValue {
    i: Int => i * 2                    // Bind as 'i' if Int
    s: String => s + "!"               // Bind as 's' if String
    user: User => user.name            // Bind as 'user' if User type
}

2. Anonymous Structural Matching #

Match on structure without requiring specific type names:

match anyValue {
    { name, age } => print("${name} is ${age}")        // ANY type with name, age
    { x, y, z } => print("3D point: ${x},${y},${z}")   // ANY type with x, y, z
    { id } => print("Has ID: ${id}")                    // ANY type with id field
}

3. Named Structural Matching #

Bind the whole object AND destructure fields:

match anyValue {
    person: { name, age } => {
        print("Person: ${person}")      // Access whole object
        print("Name: ${name}")          // Access destructured field
        print("Age: ${age}")            // Access destructured field
    }
    point: { x, y } => calculateDistance(point, origin)
}

4. Mixed Type and Structural Patterns #

match anyValue {
    user: User { id, name } => print("User ${id}: ${name}")     // Explicit type
    { email, active } => print("Has email: ${email}")           // Structural only
    data: { values: Array<Int> } => processArray(data.values)   // Nested types
    _ => print("Unknown structure")
}

8.5 Result Type Pattern Matching (Arithmetic Expressions) #

🔥 CRITICAL: All arithmetic expressions return Result<T, MathError>. You MUST handle them with pattern matching.

Simple Arithmetic Result Handling #

let calculation = 1 + 3 + (300 / 5)  // Result<int, MathError>

match calculation {
    Success { value } => print("Result: ${value}")
    Error { message } => print("Math error: ${message}")
}

Compound Expression Examples (CRYSTAL CLEAR) #

// Each of these returns a SINGLE Result for the ENTIRE expression
let simple = 10 + 5                    // Result<int, MathError>
let complex = 1 + 2 * 3 - 4 / 2        // Result<int, MathError>  
let nested = ((a + b) * c) / (d - e)   // Result<int, MathError>

// Handle ALL of them the SAME WAY
match simple {
    Success { value } => print("10 + 5 = ${value}")
    Error { message } => print("Failed: ${message}")
}

match complex {
    Success { value } => print("Complex calc = ${value}")
    Error { message } => print("Overflow/error: ${message}")
}

match nested {
    Success { value } => print("Nested result = ${value}")
    Error { message } => print("Division by zero or overflow: ${message}")
}

Function Return Results #

fn calculate(x: int, y: int) -> Result<int, MathError> = x + y * 2 - 5

let result = calculate(10, 3)  // Result<int, MathError>
match result {
    Success { value } => print("Function result: ${value}")
    Error { message } => print("Function failed: ${message}")
}

Advanced Result Chains #

// Multiple Results in sequence
let step1 = 100 + 50        // Result<int, MathError>
let step2 = 200 * 3         // Result<int, MathError>

// Handle each step
match step1 {
    Success { value1 } => {
        match step2 {
            Success { value2 } => {
                let final = value1 + value2  // This is also Result<int, MathError>!
                match final {
                    Success { total } => print("Final: ${total}")
                    Error { message } => print("Final calc failed: ${message}")
                }
            }
            Error { message } => print("Step 2 failed: ${message}")
        }
    }
    Error { message } => print("Step 1 failed: ${message}")
}

8.6 Match Expression Type Safety Rules #