> ## Documentation Index
> Fetch the complete documentation index at: https://docs.astrakairo.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Kairo Control Flow: Branching, Matching, and Bindings

> Use if/else and match for branching in Kairo, and learn how let and var bindings make control flow explicit, predictable, and easy to reason about.

Kairo keeps control flow explicit and honest. There is no truthy/falsy coercion — branching conditions must be `Bool`. Pattern matching with `match` handles both simple branching and exhaustive case analysis, and it works as either a statement or an expression. Local bindings distinguish mutable state (`var`) from immutable state (`let`) at the point of declaration. The result is code where the intent of every branch and binding is visible from the syntax alone.

## Local Bindings: `let` and `var`

Declare a local variable with `let` (immutable) or `var` (mutable). `let` bindings cannot be reassigned after their initial value is set.

```kairo theme={null}
let orderId: OrderId = OrderId { value: "ORD-001" }
let label: Text = "Confirmed"
```

For `let`, Kairo can often infer the type when the initializer makes it obvious. In cases where the type is not immediately clear, an explicit annotation is clearer to both the compiler and the reader.

`var` declares a binding that you intend to reassign. In v0.1, `var` local bindings require an explicit type annotation.

```kairo theme={null}
var retryCount: Int32 = 0
retryCount = retryCount + 1
```

<Note>
  Prefer `let` for all bindings by default. Reach for `var` only when you genuinely need to reassign the binding later in the same scope. Unnecessary mutability makes code harder to reason about.
</Note>

## `if` / `else`

Use `if` and `else` for boolean branching. The condition must be a `Bool` expression — Kairo does not coerce non-boolean values to `true` or `false`.

```kairo theme={null}
if order.isConfirmed {
    notifyCustomer(order.customerId)
} else {
    flagForReview(order.id)
}
```

Chain multiple conditions with `else if`:

```kairo theme={null}
if score >= 90 {
    return Grade.Excellent
} else if score >= 70 {
    return Grade.Passing
} else {
    return Grade.Failing
}
```

<Warning>
  Kairo does not perform truthy/falsy coercion. Writing `if someText { ... }` or `if someObject { ... }` is a compile error. Your condition must evaluate to a `Bool`.
</Warning>

You can use `not` to negate a boolean expression:

```kairo theme={null}
if not order.isConfirmed {
    return Result.failure(OrderError.NotConfirmed)
}
```

## `match` — Pattern Matching

`match` is Kairo's primary tool for exhaustive branching. It works in two forms: a **statement form** that executes blocks, and an **expression form** that produces a value.

### Statement Form

Use the statement form when each branch performs actions or side effects. Each arm is a pattern followed directly by a block:

```kairo theme={null}
match status {
    OrderStatus.Pending {
        Pulse.Console.out.writeLine("Awaiting confirmation")
    }
    OrderStatus.Confirmed {
        Pulse.Console.out.writeLine("Order confirmed")
    }
    OrderStatus.Shipped {
        Pulse.Console.out.writeLine("On the way")
    }
    else {
        Pulse.Console.out.writeLine("Order complete")
    }
}
```

### Expression Form

Use the expression form when each branch produces a value and you want to bind the result. Each arm uses `=>` and the `else` arm provides the fallback:

```kairo theme={null}
let label: Text = match status {
    OrderStatus.Pending   => "Pending"
    OrderStatus.Confirmed => "Confirmed"
    OrderStatus.Shipped   => "Shipped"
    else                  => "Other"
}
```

<Tip>
  The expression form eliminates intermediate `var` bindings that exist only to be assigned in branches. Wherever a `match` produces a single type in all arms, prefer the expression form.
</Tip>

### Matching on Nullable Values

Use `null` as a pattern to handle the absent case of a nullable type:

```kairo theme={null}
let displayName: Text = match customer.nickname {
    null => customer.fullName
    else => customer.nickname
}
```

### Matching on Boolean Results

The canonical way to inspect a `Result<T, E>` is to match on its `.isSuccess` property:

```kairo theme={null}
match outcome.isSuccess {
    true {
        process(outcome.value)
    }
    false {
        handleError(outcome.error)
    }
}
```

### The `else` Arm

Every `match` that does not enumerate all possible cases must include an `else` arm as a catch-all. For `enum` types with a known set of cases, you can omit `else` if every case is listed explicitly — but the compiler will warn if cases are missing.

## `return` Statement

Use `return` to exit the current function and optionally produce a value. `return` can appear anywhere in a function body — execution of the function stops immediately.

```kairo theme={null}
public func classify(amount: Decimal): Text {
    if amount < 0 {
        return "Negative"
    }
    if amount == 0 {
        return "Zero"
    }
    return "Positive"
}
```

In a function with no return type, use a bare `return` to exit early:

```kairo theme={null}
func logIfVerbose(message: Text) {
    if not verboseMode {
        return
    }
    Pulse.Console.out.writeLine(message)
}
```

## `async` / `await`

`async` and `await` are Kairo's explicit suspension mechanism. Declare a function `async` to allow it to suspend, and use `await` at each suspension point inside it.

```kairo theme={null}
public async func loadOrder(id: OrderId): Result<Order, LoadError> {
    let response = await OrderRepository.fetch(id: id)

    match response.isSuccess {
        true  { return Result.success(response.value) }
        false { return Result.failure(LoadError.NotFound) }
    }
}
```

`await` is only valid inside an `async` function. There is no implicit async promotion — a regular function cannot silently suspend.

<Note>
  `async` / `await` are covered in detail in the [Functions](/language/functions) page. They are listed here because `await` is an expression that participates in control flow — it suspends the current function until the awaited operation completes, then resumes from that point.
</Note>

## Loops: `for` and `while` (Reserved in v0.1)

`for` and `while` are reserved keywords in Kairo v0.1. Loop semantics are defined in the language specification but are not yet available in this version. If you need to iterate over a collection, use collection methods or recursive `func` patterns in the meantime.

<Note>
  `for` and `while` are intentionally reserved in v0.1. Their semantics — including how they interact with immutable collections and `Result`-returning closures — will be introduced in a future release. Using either keyword as an identifier is a compile error.
</Note>

## Quick Reference

<Tabs>
  <Tab title="if / else">
    ```kairo theme={null}
    if condition {
        // condition is true
    } else if otherCondition {
        // otherCondition is true
    } else {
        // fallback
    }
    ```
  </Tab>

  <Tab title="match (statement)">
    ```kairo theme={null}
    match value {
        Case.One { /* ... */ }
        Case.Two { /* ... */ }
        else     { /* ... */ }
    }
    ```
  </Tab>

  <Tab title="match (expression)">
    ```kairo theme={null}
    let result: Text = match value {
        Case.One => "One"
        Case.Two => "Two"
        else     => "Other"
    }
    ```
  </Tab>

  <Tab title="let / var">
    ```kairo theme={null}
    let name: Text = "Kairo"   // immutable
    var count: Int32 = 0       // mutable
    count = count + 1
    ```
  </Tab>
</Tabs>
