Throwing
Sometimes, deeply nested expressions need to exit early from a computation, or pass a value directly back up to a higher block without further processing.
Wolf implements a non-viral, strictly-typed “throwing” and “catching” mechanism to allow nested expressions to exit early.
Catching
A block can be prefixed with catch
. This indicates that the block will catch
any value thrown to it. When that happens, the block will evaluate to that
thrown value.
let can_catch = catch (2)
catch
does not change what the block returns by default.
-- These two expressions are identical.
let foo = (2)
let foo = catch (2)
Throwing
While inside of a catch
block, any expression can start with throw
. This
short-circuits the rest of the computation and throws the value to the nearest
ancestor catch
block.
let three = catch (
-- 4 and 5 are not evaluated.
1 -> 2 -> throw 3 -> 4 -> 5
)
Throwing is strictly local; you cannot throw to a catch
block elsewhere in the
source code.
-- This is not allowed.
let foo = fn [message : str] throw message
let bar = catch ( foo ["Hello world"] )
All thrown values must evaluate to a type compatible with the catch
block.
-- This is not allowed.
let foo = catch ( if true then throw "string" else 5 )