Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Control Flow

Cambrian provides two control flow expressions: if/else for conditional branching and match for pattern matching. Both are expressions – they evaluate to a value.

if / else

The if/else expression evaluates a boolean condition and returns the value of the corresponding branch:

let fee = if amount > threshold { high_fee } else { low_fee };

Basic Form

if condition {
    value_when_true
} else {
    value_when_false
}

Both branches must produce values of the same type when used as an expression.

Chained Conditions

Multiple conditions can be chained with else if:

let tier = if amount >= 10000 {
    "gold"
} else if amount >= 1000 {
    "silver"
} else {
    "bronze"
};

In Member Transforms

if/else is frequently used in member transforms to compute new state conditionally:

m_high_score: u64 {
    in submit(score) => if score > m_high_score {
        score
    } else {
        m_high_score
    }
}

In Pure Functions

Pure functions commonly use if/else as their body:

pure fn max(a: u64, b: u64) -> u64 {
    if a >= b { a } else { b }
}

pure fn clamp(val: u64, lo: u64, hi: u64) -> u64 {
    if val < lo { lo }
    else if val > hi { hi }
    else { val }
}

match

The match expression compares a value against a series of patterns and executes the first matching branch:

let description = match status {
    Status::Active => "running",
    Status::Paused => "paused",
    Status::Closed => "finished",
    _ => "unknown"
};

Syntax

match expression {
    Pattern1 => result1,
    Pattern2 => result2,
    _ => default_result
}

Each arm consists of a pattern, the => arrow, and a result expression. Arms are separated by commas.

Matching Enum Variants

The most common use of match is destructuring enums:

enum Command {
    Deposit(U256),
    Withdraw(U256),
    Freeze
}

let response = match cmd {
    Command::Deposit(amount) => amount,
    Command::Withdraw(amount) => amount,
    Command::Freeze => 0
};

The variable names in data variant patterns (like amount above) bind the associated data for use in the result expression.

Matching Option

Option<T> is commonly matched to handle present and absent values:

let balance = match m_balances.get(account) {
    some(val) => val,
    none => 0
};

Block Bodies

When a match arm needs multiple computations, use a block:

let result = match action {
    Action::Transfer(to, amount) => {
        let fee = amount * 3 / 100;
        amount - fee
    },
    Action::Refund(amount) => amount,
    _ => 0
};

Wildcard Pattern

The _ pattern matches any value. It is typically used as the last arm to handle all remaining cases:

match value {
    0 => "zero",
    1 => "one",
    _ => "other"
}

In Route Actions

match can be used inside route actions for conditional dispatch:

routes {
    execute(action: Action) => [
        match action {
            Action::Transfer(amount) => [
                ~> m_recipient with { value: amount }
            ],
            Action::Pause => []
        }
    ]
}

Exhaustiveness

The compiler checks that match expressions cover all possible variants when matching on an enum. If any variant is missing and no wildcard _ arm is present, the compiler will report an error. This guarantees that no case is accidentally overlooked.