Standard library reference

Everything here is written in Vela and lives under lib/. The prelude is always in scope; everything else needs a use.

Generate an always-current version from the source with vela doc.


Prelude — always in scope

Conversions and inspection

functionmeaning
str(x) -> Strtext for any value; uses T.to_str when the type defines it
int(x) -> Intfrom Float (truncates), Byte, Bool
int(s: Str) -> ?Intparse, nil when malformed
float(x) -> Floatfrom Int, Byte
float(s: Str) -> ?Floatparse, nil when malformed
byte(n: Int) -> Bytewraps modulo 256
bool(n: Int) -> Booln != 0
len(x) -> Intbytes in a Str, elements in a list or map

Output and failure

functionmeaning
print(x...), println(x...)write to standard output
panic(msg: Str)print to stderr and exit 101; does not return
assert(c: Bool, msg: Str = ...)fail unless c
assert_eq(a, b), assert_ne(a, b)fail with both values shown
ok(v), err(msg), err_code(msg, code)build a !T
voidthe value of type Void

Buf — the string builder

let b = buf()                  // or buf_with(expected_size)
for x in xs {
    b.push(str(x))
    b.push_byte(',')
}
let s = b.str()

Str is immutable, so s = s + piece in a loop copies everything each time and is quadratic. Reach for buf() whenever you build a string in a loop. Buf is in the prelude, so no import is needed.

buf() buf_with(cap) Buf.push(s) Buf.push_byte(c) Buf.len() Buf.clear() Buf.str()

Str

len char_len is_empty upper lower trim starts_with ends_with contains index_of split words lines replace repeat at bytes chars to_int to_float hash

Indexing yields a Byte and len counts bytes; chars() and char_len() decode UTF-8. Slicing yields a copy. Strings are immutable.

List[T]

len is_empty push pop first last insert remove clear copy reverse map filter fold each any all find index_of contains sort sort_by join

sort and sort_by are an in-place heapsort: O(n log n) always, and neither allocates. sort() needs < on the element type; a type without it reports the error at the call site.

Map[K, V]

len is_empty has delete clear keys values get_or

m[k] yields ?V; m[k] = v inserts or updates. Iteration order is unspecified. Keys may be any type with structural equality.

Int, Float, Byte, Range

Int:    abs min max clamp hex
Float:  abs floor ceil round min max sqrt pow is_nan
Byte:   is_digit is_alpha is_alnum is_space str
Range:  len list

Float.sqrt compiles to a single sqrtsd.


std/io

io.print(s)              io.println(s)
io.eprint(s)             io.eprintln(s)
io.read_line() -> ?Str   io.read_all() -> Str    io.read_exact(n) -> Str
io.write(fd, s) -> Int   io.read(fd, n) -> Str
io.STDIN io.STDOUT io.STDERR

Standard input is buffered; output is not, so a println is exactly one write.

std/fs

fs.read_file(path)  -> !Str          fs.write_file(path, text)  -> !Void
fs.read_lines(path) -> ![Str]        fs.append_file(path, text) -> !Void
fs.exists(path) -> Bool              fs.size(path) -> !Int
fs.is_dir(path) -> Bool              fs.is_file(path) -> Bool
fs.remove(path) -> !Void             fs.rename(from, to) -> !Void
fs.mkdir(path) -> !Void              fs.mkdir_all(path) -> !Void
fs.rmdir(path) -> !Void              fs.read_dir(path) -> ![Str]

fs.open(path) -> !File               fs.create(path) -> !File
fs.append(path) -> !File
File.read(n) -> Str    File.read_all() -> Str
File.write(s) -> !Int  File.close()

Errors carry the path and a readable reason (no such file or directory, permission denied, ...).

std/os

os.args() -> [Str]              os.env() -> {Str: Str}
os.getenv(name) -> ?Str         os.exit(code)
os.cwd() -> Str                 os.chdir(path) -> !Void
os.pid() -> Int                 os.sleep_ms(ms)
os.exe_path() -> Str

std/path

path.join([parts]) -> Str      path.dir(p) -> Str      path.base(p) -> Str
path.ext(p) -> Str             path.stem(p) -> Str
path.is_absolute(p) -> Bool    path.normalize(p) -> Str

Purely textual: nothing here touches the filesystem.

std/math

math.PI math.E math.TAU math.INF math.NAN
math.abs  math.sqrt math.floor math.ceil math.round math.min math.max
math.sin  math.cos  math.tan
math.log  math.log2 math.log10 math.exp  math.pow
math.atan math.atan2 math.hypot

The elementary functions use argument reduction plus series evaluation, and are accurate to about 1e-12 over their usual ranges. sqrt is exact.

std/rand

rand.seed(n)          rand.seed_from_clock()
rand.next() -> Int    rand.int_below(n) -> Int   rand.range(lo, hi) -> Int
rand.float01() -> Float                          rand.chance(p) -> Bool
rand.shuffle(xs)      rand.pick(xs) -> ?T

xoshiro256\*\*. The same seed always produces the same sequence.

std/time

time.now_ns() time.now_ms() time.now_s()   time.mono_ns()
time.now() -> DateTime                     time.utc(secs) -> DateTime
time.is_leap(year) -> Bool                 time.duration_str(ns) -> Str
DateTime{ year, month, day, hour, minute, second }   DateTime.to_str()  // ISO 8601

Use mono_ns for elapsed time; it is unaffected by clock adjustments.

std/sort

sort.ints(xs)   sort.floats(xs)   sort.strs(xs)   sort.by(xs, less)
sort.search_ints(xs, v) -> Int    sort.is_sorted(xs, less) -> Bool

std/json

json.parse(text) -> !Json
Json.to_str() -> Str          Json.pretty() -> Str
Json.get(key) -> ?Json        Json.at(i) -> ?Json
Json.as_str() -> ?Str         Json.as_int() -> ?Int
Json.as_float() -> ?Float     Json.as_bool() -> ?Bool

enum Json { Null, Bool(Bool), Num(Float), Str(Str), List([Json]), Obj({Str: Json}) }

Parse errors name the byte offset. Object keys are sorted on output, so the same document always serialises identically.

std/net

net.listen(port) -> !Listener      Listener.accept() -> !Conn   Listener.close()
net.connect(host, port) -> !Conn
Conn.write(s) -> !Int              Conn.read(n) -> Str
Conn.read_all() -> Str             Conn.read_until(marker) -> Str
Conn.close()
net.parse_ip(s) -> ?Int

IPv4 TCP over raw syscalls. host must be a dotted quad — there is no resolver.

std/process

process.run(args) -> !Output       // waits, captures stdout and stderr
process.spawn(args) -> !Int        // waits, inherits the parent's streams
process.which(name) -> ?Str        // PATH lookup
process.kill(pid, sig) -> !Void
Output{ status: Int, stdout: Str, stderr: Str }

std/fmt

fmt.pad_left(s, w)  fmt.pad_right(s, w)  fmt.center(s, w)
fmt.zero_pad(n, w)  fmt.fixed(v, places) fmt.commas(n)  fmt.bytes(n)
fmt.table(rows) -> Str

std/testing

assert_near(a, b, eps)   assert_contains(s, sub)   assert_has(xs, v)
assert_ok(r) -> T        assert_err(r)

assert, assert_eq and assert_ne are in the prelude. A test body is a !Void function, so ? works inside it and a propagated error fails the test.

core

The runtime. Import it only when you need the collector's statistics or the string builder.

core.arch() -> Str              // "x86_64" or "arm64"
core.gc_collections() -> Int    core.gc_live_bytes() -> Int
core.gc_heap_bytes()  -> Int    core.gc_collect()

core.buf() -> Buf               core.buf_with(cap) -> Buf
Buf.push(s)  Buf.push_byte(c)   Buf.len() -> Int  Buf.clear()  Buf.str() -> Str

Buf is what you want whenever a string is built in a loop: + copies, and n concatenations of a growing string is O(n²).

Everything else in core — the allocator, the collector, the string and collection primitives, the type-descriptor walker — is implementation and may change.