Builtins and Intrinsics
Vex provides a robust, always-available set of builtin and intrinsic helpers covering:
- Runtime I/O and debugging
- Panic and development traps
- Low-level memory access
- Timing helpers
- Compile-time reflection and diagnostics
- Autograd intrinsics
This page documents the stable builtins and their prefix conventions.
Prefix Families
Builtin names fall into three distinct groups:
#...for Compile-Time helpers (zero runtime cost).$...for Runtime helpers (has runtime execution cost).@...for Autograd helpers.
Design Principle: No Runtime Cost
All compile-time features are prefixed with # (e.g., #sizeof, #alignof, #typeName, #if, #for). The $ prefix is reserved exclusively for runtime features that call compiler-internal runtime helper intrinsics (such as $print, $println, and $now), indicating they have a runtime execution cost.
Runtime I/O and Debugging
$print("partial line")
$println("done")
$eprint("warning: ")
$eprintln("bad state")
let rendered = $format("{0}:{1}", host, port)
let value = $dbg(rendered)The runtime builtins include:
$print$println$eprint$eprintln$format$dbg(prints expression and value, then returns it)
Runtime Traps and Development Helpers
$panic("fatal error")
$todo("finish this branch")
$unreachable()
$assertEq(left, right)$panicaborts execution immediately.$todomarks unfinished runtime paths.$unreachablesignals to the compiler that this code path is impossible.$assertEqis a runtime equality assertion with structured failure output.
Memory and Low-Level Helpers
$drop(resource)
let value = $load(ptr)
$store(ptr_mut, value)
let slice = $ptrToSlice(raw_ptr, len)- Prefer
Ptr<T>,Span<T>, andRawBufover raw pointer helpers. - Treat
$load,$store, and$ptrToSliceas unsafe building blocks. - Use
$droponly when early destruction is required.
Timing
let start = $now()
work()
let end = $now()Both $monotonicNow() and $now() resolve to the same high-resolution monotonic timing helper in the runtime.
Layout, Shape, and Reflection
let size = #sizeof<i64>()
let align = #alignof<f64>()
let ty_name = #typeName<Vec<i32>>()
let len = $len(v)
let rank = $rank(tensor)
let shape = $shape(tensor)Compile-time reflection helpers also include:
#typeInfo<T>()#getField(value, field)#setField(target, field, value)#fieldCount<T>()#variantCount<E>()#len<T>()/#length<T>()(static length)#rank<T>()/#ndim<T>()(tensor dimensions)#shape<T>()(static shape tuple)#tupleLen<T>()/#arrayLen<T>()(tuple/array lengths)#elementType<T>()/#implements<T, Contract>()(element/contract query)#isPowerOf2<T>(val)/#isPowerOfTwo<T>(val)(checks if val is power of 2)#offset_ptr_idx(base, index, stride)(computes raw pointer offset)#ptr_write(ptr, value)(writes value directly to raw address)#format(fmt, ...)(compile-time formatting parsing helper)
Compile-Time Type Predicates
#isStruct<T>(),#isEnum<T>(),#isPrimitive<T>()#isInteger<T>(),#isFloat<T>(),#isSigned<T>()#isPointer<T>(),#isArray<T>(),#isTuple<T>()#isCopy<T>(),#needsDrop<T>(),#isReference<T>()#isFunction<T>(),#isGeneric<T>(),#sameType<T, U>()
If you are doing compile-time code generation or reflection work, see Comptime.
Compile-Time Diagnostics and Embedding
#staticAssert(#fieldCount<User>() > 0, "User must stay non-empty")
#warning("legacy path compiled")
let home = #env("HOME")
let text = #includeStr("banner.txt")
let bytes = #includeBytes("blob.bin")
let expr = #debugExpr(5 + 3)
let joined = #concat("hello", " ", "vex")
let name = #concatIdents(foo, bar)#staticAssert#compileError#warning#debugExpr#env#includeStr#includeBytes#concat#stringify#concatIdents
Autograd Builtins
Autograd uses @... as the primary syntax:
let x = @param(2.0)
let y = Math.sin(x)
$println(@val(y))
$println(@grad(y))@param@val@grad@detach
Guidance
- Prefer ordinary language constructs first and reach for builtins only when necessary.
- Prefer
Ptr<T>,Span<T>, andRawBufover$load,$store, and$ptrToSlice. - Keep
$dbgand$todotemporary. - Prefer
#...spellings for all compile-time helpers.