Built-in Functions
A small set of functions is provided by the compiler rather than
the standard library. They are spelled as ordinary function calls —
Verum has no !-suffix macros like Rust — but their implementation is
hard-wired.
This page is the authoritative registry, organised by category.
Grammar reference:
builtin_call = builtin_name , '(' , [ argument_list ] , ')' ;
builtin_io = 'print' | 'eprint' ;
builtin_assertion = 'assert' | 'assert_eq' | 'assert_ne' | 'debug_assert' ;
builtin_control_flow = 'panic' | 'unreachable' | 'unimplemented' | 'todo' ;
builtin_async = 'join' | 'try_join' | 'join_all' | 'select_any' | 'ready' | 'pin' ;
I/O
print
fn print(args: ...Display);
Writes its arguments to standard output, separated by spaces, followed
by a newline. Accepts any number of values implementing Display.
print("hello"); // hello
print("x =", x, "y =", y); // x = 3 y = 4
print(f"value: {x}"); // value: 3 (format string)
print is a built-in — functions calling it do not need a
using [...] clause. Standard output is one of a small set of
built-in effects (print, eprint, println, assert, panic,
unreachable, todo, unimplemented) that bypass the user-ctx
mechanism. User-declared contexts (Logger, Database, Clock, ...)
still require their explicit using [...] declaration.
eprint
fn eprint(args: ...Display);
Identical to print, writing to standard error.
eprint(f"Error: could not open {path}");
Assertions
Assertions are runtime checks that call panic on failure. Under
@verify(static) or @verify(formal), the SMT engine also checks
them at compile time — a failing assertion with a provable
counter-example is a compile error.
assert
fn assert(condition: Bool);
fn assert(condition: Bool, message: Text);
Panics unless condition is true.
assert(x > 0);
assert(list.len() > 0, "list must be non-empty");
assert_eq / assert_ne
fn assert_eq<T: Eq + Debug>(left: T, right: T);
fn assert_ne<T: Eq + Debug>(left: T, right: T);
Panics with both values formatted when inequality is detected (or
equality for assert_ne). Faster than writing assert(a == b) — the
failure message includes the actual values.
assert_eq(result, expected);
assert_ne(connection_id, 0);
debug_assert
fn debug_assert(condition: Bool);
fn debug_assert(condition: Bool, message: Text);
Same as assert, but elided in release builds (verum build --release). Use for expensive invariants in hot paths.
debug_assert(balance >= 0, "invariant broken after ledger update");
Control flow
These functions return the never type (!). The compiler treats
their callers as diverging — no further code in the scope is reachable.
panic
fn panic(message: Text) -> !;
fn panic(args: ...Display) -> !;
Terminates the current task or process with an error message. In a
thread, unwinds (if unwinding is enabled) and propagates to the
nursery; in #[no_std], aborts.
panic(f"unexpected state {state}");
panic("not implemented for tagged variant");
unreachable
fn unreachable() -> !;
fn unreachable(message: Text) -> !;
Panics with an "unreachable code reached" message. Use in match arms that exhaust the input but cannot be proven exhaustive to the compiler, or at points invariants guarantee never execute.
match tag {
Kind.Read => handle_read(),
Kind.Write => handle_write(),
_ => unreachable(),
}
unimplemented
fn unimplemented() -> !;
fn unimplemented(reason: Text) -> !;
Panics with "not yet implemented". Semantically equivalent to
todo(); use unimplemented when you plan to leave the body
unimplemented (e.g. an interface stub the user must fill).
todo
fn todo() -> !;
fn todo(note: Text) -> !;
Panics with "todo". Use during development to leave placeholders.
The verum lint tool reports todo() calls as warnings.
fn render(shape: Shape) -> Pixels {
match shape {
Shape.Rect(r) => rect_pixels(r),
Shape.Ellipse(_) => todo("ellipse rendering"),
}
}
Async primitives
All async built-ins require an async runtime context; see async-concurrency.
join
async fn join<A, B>(a: Future<A>, b: Future<B>) -> (A, B);
async fn join<A, B, C>(a: Future<A>, b: Future<B>, c: Future<C>) -> (A, B, C);
// …up to 8-ary
Runs all futures concurrently. Returns their results as a tuple once all have completed. If any future panics, the others are cancelled and the panic is re-raised.
async fn load_page() -> Page using [Http, Database] {
let (hdr, body, footer) = join(fetch_header(), fetch_body(), fetch_footer()).await;
Page { header: hdr, body, footer }
}
try_join
async fn try_join<A, B, E>(
a: Future<Result<A, E>>,
b: Future<Result<B, E>>,
) -> Result<(A, B), E>;
// …up to 8-ary
Like join, but short-circuits on the first Err. All tuple items
must have the same error type.
let (rows, meta) = try_join(db.rows(), db.meta()).await?;
join_all
async fn join_all<T>(futures: Vec<Future<T>>) -> Vec<T>;
Runs a variable number of identical-result-type futures. Returns all
results as a Vec<T>. Any panic propagates.
select_any
async fn select_any<T>(futures: Vec<Future<T>>) -> (T, usize, Vec<Future<T>>);
Completes when the first future completes. Returns the result, the index of the winning future, and the remaining (unpolled) futures.
let (winner, idx, rest) = select_any(vec![fast, medium, slow]).await;
print(f"task {idx} won with {winner}");
// `rest` is still live — drop or reawait.
ready
fn ready<T>(value: T) -> Future<T>;
Wraps a synchronous value in a Future<T> that is immediately ready.
Useful for stubs and control flow that expects a future.
let fut: Future<Int> = ready(42);
let x = fut.await; // 42
pin
fn pin<T>(value: T) -> Pin<T>;
Pins a value to its current memory location so that self-referential
futures can be polled safely. Most users encounter pin only through
the async expansion — manual use is rarely needed.
Time & system intrinsics
From core.intrinsics.runtime.time — auto-mounted in every crate.
These are direct wrappers over OS clocks; cost is one syscall or a
single mach_absolute_time / QueryPerformanceCounter call on the
respective platform.
monotonic_nanos
fn monotonic_nanos() -> UInt64
Nanoseconds from an opaque, monotonically-increasing reference point
(kernel boot on Linux; mach_absolute_time on macOS). The returned
value has no Unix-epoch meaning — use it only for differences.
let t0 = monotonic_nanos();
do_work();
let elapsed_ns = monotonic_nanos() - t0;
Immune to wall-clock adjustments (NTP step, DST, user-set). The single correct choice for benchmarking, timeouts, and rate-limiting.
realtime_nanos
fn realtime_nanos() -> UInt64
Nanoseconds since the Unix epoch (1970-01-01T00:00:00Z UTC). Use for timestamps and logs; not for measuring intervals — the clock can go backwards.
realtime_secs
fn realtime_secs() -> Int64
Whole seconds since the Unix epoch. Same caveats as
realtime_nanos.
num_cpus
fn num_cpus() -> Int
Logical-CPU count as the kernel sees it. Use when sizing thread pools
or work-queue fan-out. Matches what the async scheduler would auto-
pick when async_worker_threads = 0.
sleep_ms / sleep_ns
fn sleep_ms(ms: Int)
fn sleep_ns(ns: Int)
Block the current thread (or task, when called from an async fn)
for at least the given duration. Precision is OS-dependent — on Linux
sleep_ns resolves to nanosleep; on macOS to mach_wait_until.
Use from async code sparingly — prefer cancellable sleeps exposed by
the async runtime (time.sleep(...).await).
Format strings (f"...")
Not a function, but tightly coupled to print. f"..." is a literal
whose {expr} splices are type-checked. See
Tagged Literals for the grammar.
Format specifications use the colon separator:
f"{value:04}" // pad with zeros to width 4
f"{price:.2}" // 2 decimal places
f"{p:>10}" // right-align, width 10
f"{msg:^.20}" // centre, truncate to 20
f"{bytes:#x}" // hex with 0x prefix
f"{value:?}" // debug form
Format spec mini-language:
[fill][align][sign][#][0][width][.precision][type]
align = < | > | ^
sign = + | -
type = x | X | o | b | e | E | f | F | ?
What is not a built-in
A few things look built-in but are standard library or grammar constructs:
select { … }— an expression, not a call. See async-concurrency.nursery { … }— an expression with options and handlers.format— no such function; usef"...".matches!— Verum uses theisoperator:value is Some(x).vec!/list!/hashmap!— use literal syntax ([1, 2],{k: v, ...}) or constructors (List.of(...),Map.of(...)).
See also
- Meta Functions — the
@-prefix compile-time counterparts (@const,@cfg,@stringify). - async-concurrency —
select,nursery,spawn. - Tagged Literals —
f"...".