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

Expressions

In Cambrian, most constructs are expressions – they evaluate to a value. This includes arithmetic, comparisons, if/else, match, and blocks. This design enables a concise, functional style where the last expression in a block becomes its value.

Expression Categories

CategoryOperators / FormsChapter
Arithmetic+ - * / % (checked); +% -% *% (wrapping)Arithmetic and Logic
Comparison==, !=, <, <=, >, >=Arithmetic and Logic
Logical&&, ||, !Arithmetic and Logic
Bitwise&, |, ^, <<, >>Arithmetic and Logic
Control flowif/else, matchControl Flow
Iterationfor x in iter { body }See Iteration (for) below
Blocks{ let a = ...; expr }Blocks and Let Bindings
Field accessrecord.field, map[key]Method Calls and Field Access
Method callslist.len(), map.get(key)Method Calls and Field Access
Type castsexpr as TypeMethod Calls and Field Access

Everything Is an Expression

Unlike imperative languages where if is a statement, in Cambrian if/else produces a value:

let fee = if amount > 1000 { 10 } else { 5 };

Similarly, match is an expression:

let label = match status {
    Status::Active => "active",
    _ => "inactive"
};

And blocks evaluate to their last expression:

let result = {
    let a = compute_x();
    let b = compute_y();
    a + b
};

Expressions in Context

Expressions appear in several contexts throughout a Cambrian program:

  • Member transforms – the body of a member transform is an expression that produces the new state value:
m_balance: U256 {
    in deposit(amount) => m_balance + amount
}
  • Where clauses – preconditions are boolean expressions:
where amount > 0 : throw 100
  • Route actions – expressions appear in let bindings, message arguments, and conditional guards:
let fee = amount * 3 / 100;
Transfer(amount - fee) ~> recipient
  • Pure functions – the function body is an expression:
pure fn clamp(val: u64, lo: u64, hi: u64) -> u64 {
    if val < lo { lo }
    else if val > hi { hi }
    else { val }
}

Iteration (for)

Expression-level for produces a value (typically a Vec) by mapping over an iterator:

pure fn double_all(xs: Vec<u32>) -> Vec<u32> {
    for x in xs { x * 2 }
}

pure fn first_n(n: u32) -> Vec<u32> {
    for i in 0..n { i }
}

Common iterator sources:

FormMeaning
for x in lo..hi { … }Half-open integer range
for x in vec_expr { … }Each element of a Vec
for (k, v) in map { … }Key/value pairs from a HashMap
expr.fold(init, |acc, x| …)Accumulator loop (scalar, tuple, or record)

Inside a route action list, a different form sequences side effects per element — no resulting value:

airdrop(amount: U256, recipients: Vec<address>) => [
    for r in recipients => [
        ~> r with { value: amount }
    ]
]

Restrictions: action-level for cannot nest forbidden effects (V29). On EVM, supported shapes lower to a single Solidity loop. See Control Flow for if/match and Route Actions for effectful loops in routes.