Repository navigation
Torvik v1.3.0 — Ravens & Bridges
The concurrency release. Torvik programs can now run work on multiple threads — designed so data races aren't something you avoid, they're something the language gives you no way to write.
🐦⬛ Ravens: concurrent tasks
raven spawns any df function on its own OS thread — fire-and-forget, or bind a task<T> handle and collect the result with join:
set h: task<str> = raven fetch(url);
// ...other work...
fixed page: str = join(h);
- Arguments deep-copy at the spawn, so a task owns its own copy of everything it receives — after the spawn line, the two threads share nothing.
- Spawned functions must be self-contained (no globals, transitively) — enforced at compile time with an error naming the function and the global. This is what keeps the reference-counting runtime lock-free.
- Every crossable type works: all integer widths,
f64,bool,str,i128/u128, andaettvalues. - Each handle joins exactly once; a panic in a task stops the whole process immediately — background failures are never silently swallowed.
🌉 Bridges: typed channels between tasks
A bridge<T> is a buffered, thread-safe queue — the one object tasks share, protected by its own lock:
df produce(ch: bridge<i64>, n: i64) -> void {
set i: i64 = 0;
whilst i < n { send(ch, i); i += 1; }
bridge_close(ch);
}
df main() -> void {
set ch: bridge<i64> = bridge_new(4);
raven produce(ch, 10);
set total: i64 = 0;
whilst true {
set r: result<i64> = try_recv(ch);
check is_err(r) { break; }
total += unwrap(r);
}
echo!("sum: {total}");
}
- Values deep-copy on send;
recvblocks while empty;bridge_closeis idempotent and wakes everyone. try_recvreturns aresult<T>that goeserrexactly once the bridge is closed and drained — the clean end for a worker loop.- Multiple producers and consumers on one bridge are fully supported.
- A bridge's own refcount is the single atomic operation in the entire design; every other refcount in the language stays lock-free.
🧵 Strings are data; interpolation belongs to echo and fmt
String interpolation is now scoped to echo, echo!, and fmt — a string literal written directly as one of their arguments interpolates exactly as before ({name}, expressions, {{ escapes). A string literal anywhere else is plain data:
fixed css: str = ".a{color:red}"; // just characters — compiles fine now
fixed slot: str = "{{title}}"; // exactly {{title}}, no escapes needed
fixed msg: str = fmt("Hi {name}"); // fmt still interpolates
Previously every literal interpolated, so brace-heavy data — CSS, JSON, HTML templates — needed {{ escapes everywhere and could trip "undefined variable" errors on ordinary text. Code that kept interpolated literals inside echo/fmt (the documented idiom all along) is unaffected.
🔤 Variadic str_concat
str_concat(a, b, c, ...) now folds any number of arguments left-to-right — no more nesting. Calling it with one argument is a clean compile error; previously a fixed two-argument form silently dropped extra arguments, which could hide real bugs.
📚 Standard library v1.2.0
Additive growth, no breaking changes:
std::convert(new module) —to_hex,to_bin,from_hex,to_int(parsers returnresult<i64>, so bad input is recoverable)std::strings—strip_prefix,strip_suffix,is_digits,is_alpha,center,truncatestd::list—contains_int,contains_str_in,count_int,unique,take,drop,meanstd::math—pow_checked(overflow-signalling power),digit_count,at_least,at_most,ilog2
Projects can require the new floor with std = "1.2.0" in torvik.rune.
🗂 Table iteration + a memory-safety fix
table_keys(t)returns every key as a sortedlist<str>(sorted so loops over a table are reproducible — hash order shifts as a table resizes). Iterate the keys, fetch values withtable_get.- Fixed: functions returning a
tableorbaghanded back freed memory (a missing +1-on-return retain).fixed cfg: table<str, str> = read_config(path);now works exactly as you'd expect.
🔧 Also in this release
- File-system surface for real tools:
dir_list,fs_is_dir, binary-safefs_copy, recoverable I/O viatry_writefile/try_appendline/try_fs_copy, and a newunused_resultwarning category. - The lexer's two keyword lists are now one —
is_keywordderives fromkeyword_for, eliminating an entire drift-bug class. - Installer hardening: std modules are now derived from
std.tvitself, so a new module can never be silently skipped again; the Windows installer also gained the compiler-lib sources it was missing. - Test suite grown from 100 to 123 cases, including deterministic concurrency tests (no sleeps — ordering is forced by joins and bridge blocking).
📖 Documentation
The Language Guide has a full new chapter — Concurrency: ravens and bridges — covering the ownership model, the self-contained rule and its why, and the worker-loop pattern. STDLIB.md, the Roadmap, and the wiki are all updated.
Install
Linux
curl -fsSL https://raw.githubusercontent.com/torvik-lang/torvik/main/linux/install.sh | sh
Windows (PowerShell)
iwr -useb https://raw.githubusercontent.com/torvik-lang/torvik/main/windows/install.ps1 | iex
Already installed? rune update brings you to v1.3.0.
Full details in the CHANGELOG. Binaries for Linux x86-64 and Windows x86-64 are attached below.
Self-hosting, compiled to native via LLVM. No VM, no GC — automatic reference counting, now lock-free across threads by design.