Control Flow & Errors

Tao has one if, one switch, one loop, one leave — and it reports errors by value, not by exception.

if

if is an expression. Parentheses around the condition are optional, and else if chains naturally. Without an else, a false condition yields None.

if x { 1 } else { 2 }

if False { 1 } else if True { 3 } else { 2 }   // 3

switch

switch is an expression. Arms match the value with ==; the optional else arm catches everything else. Without a match, the result is None.

switch n {
  1 => 100
  2 => 200
  else => -1
}

loop and leave

loop repeats forever. leave exits the innermost loop; using it outside a loop is an error.

let mut i = 0
loop {
  if i == 3 { leave }
  i = i + 1
}

return

return expr returns from the enclosing function. Without an explicit return, a function’s body evaluates to its last statement.

fun sign(n) {
  if n < 0 { return -1 }
  if n > 0 { return 1 }
  0
}

Errors as values

Functions that can fail return a [val, err] list: the value, and an error that is None on success.

fun readFile(path) {
  if path == "" { return [None, "empty path"] }
  return ["content", None]
}

let a, b = ...

Unpack the pair by hand:

let val, err = readFile("x")
if err != None { "failed" } else { val }

try

try expr unwraps a [val, err] pair: it yields the value when err is None, otherwise it returns the error from the current function.

fun process() {
  let content = try readFile("")
  content
}

try may only appear inside a function, and the wrapped expression must evaluate to a two-element list.