Decorators
Decorators attach to function declarations. Trigger decorators schedule when the function runs. Wrapping decorators intercept every call and delegate to the original.
Trigger decorators
A trigger decorator answers "what schedules this function?" The runtime fires the body without a direct caller.
-- lifecycle
@on_start fn boot() { setup_things() }
@on_exit fn cleanup() { close_handles() }
@on_panic fn record() { telemetry.flush() }
-- schedule
@every(1s) fn tick() { metrics.flush() }
@cron("0 * * * *") fn hourly() { rotate_logs() }
@delayed(500ms) fn warmup() { prefetch() }
-- file watching
@watch("./config.toml") fn config_changed() { config.reload() }
-- OS signals
@on_signal("INT") fn graceful() { state = "shutting_down" }The runtime stays alive while any persistent trigger is registered (@every, @cron, @on_signal, @watch). Once all have fired or been quiesced by @once, the process exits naturally.
-- @once: fire exactly once, then stop
@once @every(5s) fn one_shot() { do_thing() }
-- equivalent to: fire after 5s, then don't rescheduleTrigger-decorated functions must not take regular parameters. The runtime calls them with no arguments.
Wrapping decorators
A wrapping decorator answers "what happens around every call?" The bound name becomes a dispatcher that intercepts the call.
@memoize caches results by a key derived from the argument values. Recursive calls hit the same cache, so fib(30) only runs the body 31 times instead of exponentially many.
-- @retry(n): run up to n attempts, swallow thrown exceptions
@retry(5) fn fetch(url) { http.get(url) }
-- @trace: print call name + args before, return value after (stderr)
@trace fn handle(req) { process(req) }
-- @timed: print elapsed milliseconds after each call
@timed fn build_index() { index_files() }All wrapping decorators pass arguments through unchanged and return the body's result. @retry re-raises the final exception if every attempt fails, so the caller's try/catch still sees it.
Composing decorators
Multiple decorators on the same function stack in declaration order, outermost first: