Aver

June 12, 2026 · View on GitHub

All functions live in namespaces — no flat builtins (decision: FullNamespaceEverywhere).

Pure namespaces (no effects)

Bool namespace

Source: src/types/bool.rs

FunctionSignatureNotes
Bool.or(Bool, Bool) -> BoolLogical OR
Bool.and(Bool, Bool) -> BoolLogical AND
Bool.notBool -> BoolLogical NOT

List namespace

Source: src/types/list.rs

List is a recursive structure — use it for sequential processing with prepend, take, drop, and match [h, ..t]. For indexed access, use Vector.

FunctionSignatureNotes
List.lenList<T> -> Int
List.prepend(T, List<T>) -> List<T>O(1) prepend
List.take(List<T>, Int) -> List<T>First n elements; negative n yields []
List.drop(List<T>, Int) -> List<T>All but first n elements; negative n keeps the original list
List.concat(List<T>, List<T>) -> List<T>Concatenates two lists
List.reverseList<T> -> List<T>Returns a reversed copy
List.contains(List<T>, T) -> BoolMembership check via ==
List.zip(List<A>, List<B>) -> List<(A, B)>Pairs elements, truncates to shorter list

Vector namespace

Source: src/types/vector.rs

Vector is a persistent indexed sequence — use it for grids, buffers, lookup tables, and anywhere you need O(1) access by index. Backed by Rc<Vec<T>> with copy-on-write: set mutates in place when the vector has a single owner, clones otherwise.

FunctionSignatureNotes
Vector.new(Int, T) -> Vector<T>Create vector of N elements, all set to default
Vector.get(Vector<T>, Int) -> Option<T>O(1) indexed access
Vector.set(Vector<T>, Int, T) -> Option<Vector<T>>O(1) COW update; None if out of bounds
Vector.lenVector<T> -> Int
Vector.fromListList<T> -> Vector<T>Convert list to vector
List.fromVectorVector<T> -> List<T>Convert vector to list

Result namespace

Source: src/types/result.rs + constructors in src/vm/runtime.rs.

FunctionSignatureNotes
Result.OkT -> Result<T, E>Constructor
Result.ErrE -> Result<T, E>Constructor
Result.withDefault(Result<T, E>, T) -> TUnwrap Ok or return default

Option namespace

Source: src/types/option.rs + constructors in src/vm/runtime.rs.

FunctionSignatureNotes
Option.SomeT -> Option<T>Constructor
Option.NoneOption<T>Value (not a function)
Option.withDefault(Option<T>, T) -> TUnwrap Some or return default
Option.toResult(Option<T>, E) -> Result<T, E>Convert Option to Result

Int namespace

Source: src/types/int.rs

FunctionSignature
Int.fromStringString -> Result<Int, String>
Int.fromFloatFloat -> Int
String.fromIntInt -> String
Float.fromIntInt -> Float
Int.absInt -> Int
Int.min(Int, Int) -> Int
Int.max(Int, Int) -> Int
Int.mod(Int, Int) -> Result<Int, String>

Float namespace

Source: src/types/float.rs

FunctionSignature
Float.fromStringString -> Result<Float, String>
Float.fromIntInt -> Float
String.fromFloatFloat -> String
Float.absFloat -> Float
Float.floorFloat -> Int
Float.ceilFloat -> Int
Float.roundFloat -> Int
Float.min(Float, Float) -> Float
Float.max(Float, Float) -> Float
Float.sinFloat -> Float
Float.cosFloat -> Float
Float.sqrtFloat -> Float
Float.pow(Float, Float) -> Float
Float.atan2(Float, Float) -> Float
Float.pi() -> Float

String namespace

Source: src/types/string.rs

FunctionSignatureNotes
String.lenString -> IntNumber of characters (Unicode scalar values), on every backend
String.byteLengthString -> IntUTF-8 byte count
String.charAt(String, Int) -> Option<String>Character at character index, or Option.None on out-of-bounds
String.startsWith(String, String) -> Bool
String.endsWith(String, String) -> Bool
String.contains(String, String) -> Bool
String.slice(String, Int, Int) -> StringCharacter indices; out-of-range ends clamp
String.trimString -> String
String.split(String, String) -> List<String>
String.replace(String, String, String) -> String
String.join(List<String>, String) -> String
String.charsString -> List<String>Splits into characters (Unicode scalar values)
String.fromIntInt -> String
String.fromFloatFloat -> String
String.fromBoolBool -> String
String.toLowerString -> StringUnicode-aware lowercase
String.toUpperString -> StringUnicode-aware uppercase

Map namespace

Source: src/types/map.rs

FunctionSignatureNotes
{} (literal)The empty map; type from context (annotation or expected type). No Map.empty() builtin since 0.17 — symmetric with [] for List.
Map.fromListList<(K, V)> -> Map<K, V>Keys must be hashable (Int, Float, String, Bool)
Map.set(Map<K, V>, K, V) -> Map<K, V>Returns new map with key set
Map.get(Map<K, V>, K) -> Option<V>
Map.has(Map<K, V>, K) -> Bool
Map.remove(Map<K, V>, K) -> Map<K, V>Returns new map without key
Map.keysMap<K, V> -> List<K>
Map.valuesMap<K, V> -> List<V>
Map.entriesMap<K, V> -> List<(K, V)>
Map.lenMap<K, V> -> Int

Sets: Map<T, Unit> is the Aver way to have a set — see language.md for usage and codegen lowering.

Char namespace

Source: src/types/char.rs — not a type, operates on String/Int.

FunctionSignatureNotes
Char.toCodeString -> IntUnicode scalar value of first char
Char.fromCodeInt -> Option<String>Code point to 1-char string, Option.None for surrogates/invalid

Byte namespace

Source: src/types/byte.rs — not a type, operates on Int/String.

FunctionSignatureNotes
Byte.toHexInt -> Result<String, String>Always 2-char lowercase hex
Byte.fromHexString -> Result<Int, String>Exactly 2 hex chars required

Effectful namespaces

Namespace effect shorthand: declaring ! [ServiceName] covers all methods of that service. For example, ! [Disk] is equivalent to ! [Disk.readText, Disk.writeText, Disk.appendText, Disk.exists, Disk.delete, Disk.deleteDir, Disk.listDir, Disk.makeDir]. You can still use granular declarations like ! [Disk.readText] when you want to be precise. aver check suggests narrowing when a shorthand could be more specific.

Args namespace — use ! [Args.get]

Source: src/services/args.rs

FunctionSignatureNotes
Args.get() -> List<String>Command-line arguments passed after --

Usage: aver run file.av -- arg1 arg2 arg3

fn main() -> Unit
    ! [Args.get, Console.print]
    args = Args.get()
    Console.print(args)

Console namespace — use ! [Console.print], ! [Console.error], etc.

Source: src/services/console.rs

FunctionSignature
Console.printT -> Unit
Console.errorT -> Unit (writes to stderr)
Console.warnT -> Unit (writes to stderr)
Console.readLine() -> Result<String, String>

Http namespace — use granular effects (! [Http.get], ! [Http.post], etc.)

Source: src/services/http.rs

FunctionSignatureNotes
Http.getString -> Result<HttpResponse, String>
Http.headString -> Result<HttpResponse, String>
Http.deleteString -> Result<HttpResponse, String>
Http.post(String, String, String, Map<String, List<String>>) -> Result<HttpResponse, String>url, body, content-type, headers
Http.put(String, String, String, Map<String, List<String>>) -> Result<HttpResponse, String>
Http.patch(String, String, String, Map<String, List<String>>) -> Result<HttpResponse, String>

HttpResponse record: { status: Int, body: String, headers: Map<String, List<String>> }. Headers are a multimap — a single name can carry multiple values (Set-Cookie, Vary, …).

HttpServer namespace — use ! [HttpServer.listen] or ! [HttpServer.listenWith]

Source: src/services/http_server.rs

FunctionSignature
HttpServer.listen(Int, Fn(HttpRequest) -> HttpResponse ! [...method-level effects...]) -> Unit
HttpServer.listenWith(Int, T, Fn(T, HttpRequest) -> HttpResponse ! [...method-level effects...]) -> Unit

HttpServer.listen and HttpServer.listenWith accept top-level function values. listenWith is the preferred form when a handler needs configuration, connections, or other app state, because the context stays explicit instead of being hidden in closure capture.

This is the main intended use of function values in Aver: named handlers and callbacks with explicit types and explicit effects. Most user code still stays first-order.

The handler itself still uses exact method-level effects such as Http.get, Tcp.readLine, or Console.print. The server call does not widen those into namespace-level grants.

HttpRequest record: { method: String, path: String, body: String, headers: Map<String, List<String>> }. HttpResponse record: { status: Int, body: String, headers: Map<String, List<String>> }. Header keys are case-insensitive by convention (the runtime normalises incoming names to lowercase; outgoing should match).

The caller declares only HttpServer.listen / HttpServer.listenWith. The handler carries its own ! [...] declaration; its effects are checked on the handler function itself rather than copied onto the caller.

Disk namespace — use granular effects (! [Disk.readText], ! [Disk.writeText], etc.)

Source: src/services/disk.rs

FunctionSignatureNotes
Disk.readTextString -> Result<String, String>
Disk.writeText(String, String) -> Result<Unit, String>path, content
Disk.appendText(String, String) -> Result<Unit, String>
Disk.existsString -> Bool
Disk.deleteString -> Result<Unit, String>Files only
Disk.deleteDirString -> Result<Unit, String>Recursive
Disk.listDirString -> Result<List<String>, String>
Disk.makeDirString -> Result<Unit, String>Creates parents

Tcp namespace — use granular effects (! [Tcp.send], ! [Tcp.ping], etc.)

Source: src/services/tcp.rs

One-shot (stateless):

FunctionSignature
Tcp.send(String, Int, String) -> Result<String, String>
Tcp.ping(String, Int) -> Result<Unit, String>

Persistent connections:

FunctionSignatureNotes
Tcp.connect(String, Int) -> Result<Tcp.Connection, String>Opaque handle — see below.
Tcp.writeLine(Tcp.Connection, String) -> Result<Unit, String>Appends \r\n on the wire.
Tcp.readLineTcp.Connection -> Result<String, String>Strips the trailing \r\n; Ok("") on a clean EOF before any byte.
Tcp.closeTcp.Connection -> Result<Unit, String>Err("tcp: unknown connection ...") on a double-close.

Tcp.Connection is opaque from the surface: construction is reserved to Tcp.connect and field reads / pattern matches are rejected by the type checker. The handle is purely an identity token — the caller has nothing to inspect inside it. The underlying socket lives in a thread-local HashMap (VM / self-host / wasm-gc-bridge, keyed by AtomicU64 "tcp-N") or a 256-slot wasm-gc array (--target wasip2, slot allocated via first-free scan + monotonic counter generation). Either way, manually forging an id is impossible: the type checker rejects the constructor.

Tcp.send is stateless and ephemeral — it opens a fresh socket, writes the request bytes raw (no \r\n append), shutdown(Write) to signal end-of-request, then reads the peer's response until EOF, capped at 10 MiB. It does not touch the persistent-connection pool, so a program holding 256 live Tcp.connect handles can still issue Tcp.send to another peer. Stream errors (stream-error.last-operation-failed) surface as Result.Err("tcp: stream error"); a clean half-close (stream-error.closed) returns whatever the peer flushed.

Random namespace — use granular effects (! [Random.int], ! [Random.float])

Source: src/services/random.rs (backed by aver_rt::random)

FunctionSignatureNotes
Random.int(Int, Int) -> IntRandom integer in [min, max] inclusive
Random.float() -> FloatRandom float in [0.0, 1.0)

Time namespace — use granular effects (! [Time.now], ! [Time.unixMs], ! [Time.sleep])

Source: src/services/time.rs

FunctionSignatureNotes
Time.now() -> StringCurrent UTC timestamp string (...Z)
Time.unixMs() -> IntUnix epoch milliseconds
Time.sleepInt -> UnitSleeps current thread for ms, runtime error on negative

Terminal namespace — use granular effects (! [Terminal.clear], ! [Terminal.readKey], etc.)

Source: src/services/terminal.rs (requires terminal feature, enabled by default)

FunctionSignatureNotes
Terminal.enableRawMode() -> UnitEnter raw mode (no line buffering, no echo)
Terminal.disableRawMode() -> UnitLeave raw mode
Terminal.clear() -> UnitClear entire screen
Terminal.moveTo(Int, Int) -> UnitMove cursor to column x, row y
Terminal.printa -> UnitPrint at cursor position (no newline)
Terminal.setColorString -> UnitSet foreground: "red"/"green"/"yellow"/"blue"/"white"/"cyan"/"magenta"/"black"
Terminal.resetColor() -> UnitReset colors to default
Terminal.readKey() -> Option<String>Non-blocking poll: "up"/"down"/"left"/"right"/"esc"/"q"/char or None
Terminal.size() -> Terminal.SizeReturns Terminal.Size { width: Int, height: Int }
Terminal.hideCursor() -> UnitHide cursor
Terminal.showCursor() -> UnitShow cursor
Terminal.flush() -> UnitFlush stdout

Terminal guard: aver run installs a drop guard that restores the terminal (show cursor, reset colors, disable raw mode) even on panic or runtime error.

Env namespace — use granular effects (! [Env.get], ! [Env.set])

Source: src/services/env.rs

FunctionSignatureNotes
Env.getString -> Option<String>Returns Option.None for missing/unreadable variable
Env.set(String, String) -> UnitRuntime error on invalid key/value format

Runtime policy (aver.toml) can restrict allowed keys:

[effects.Env]
keys = ["APP_*", "PUBLIC_*"]