throw it all away
v0.1.63 makes sharing implicit, rebuilds execution on lean register bytecode, and puts an order-of-magnitude performance campaign behind the new memory rules.
v0.1.63 redraws both sides of Talk's execution contract. Shareable values no longer become programmer homework at every ownership transfer: the compiler retains them when another use remains and moves them at the last use. Underneath, a ground-up backend now carries source through ownership-aware MIR into compact register bytecode, with real programs and measured costs policing the rewrite.
For shareable values, a consuming call is now a contract with the callee, not proof that the caller will never look at the value again. If another use follows, Talk donates a retained reference to the call. If the call is the last use, the value still moves without extra runtime work. The same rule holds for an outer value consumed inside a loop, where another iteration may need it.
This is not permission to duplicate everything. Strict-linear values must still be consumed exactly once, unique values cannot be shared away, and a generic frame without the evidence needed to release a retained value remains move-only. Ordinary strings, arrays, and value aggregates get the friendlier rule.
func take(consume text: String) -> Int { text.byte_count } let text = "hello" + " world" let size = take(text) print(text.byte_count + size)
The formatted release example prints 22: take receives ownership, while the
caller's later read remains valid.
The profiled checkpoint on the 225-test talk-syntax suite cut best-of-five wall time from 8.28 seconds to 0.68 seconds. Native instructions fell from 13.15 billion to 5.81 billion, executed VM instructions from 28.8 million to 15.2 million, backend compilation from about 400 milliseconds to 66 milliseconds, and emitted bytecode from 215,508 instructions to 50,280. The widest frame fell from 48,824 registers to 148.
Those gains came from measured bottlenecks rather than one magic pass: canonical indexes replaced whole-catalog scans, call frames stopped allocating twice per call, small core operations inline, registers are reused and pooled, drops share one function per type, unwind cleanup chains share suffixes, constants ride directly in operands, join values use block parameters, dead copies fuse away, and synthesized memberwise construction emits one record operation instead of a copy-on-write field-by-field detour.
The remaining mix points to the next wins: branches and comparisons are now the largest category, while moves have fallen below 1.1 percent after peaking at 29 percent during the campaign.
The later stored-view cutover carried an honest cost: talk-syntax combined compile and run time measured 5.61 percent above its pre-flip baseline. Six benchmark archetypes were unchanged to measurement precision, strings added 1.08 percent, and the drops workload improved by 11 percent. The new benchmark corpus keeps eight workloads and their outputs pinned so future memory convenience cannot quietly erase the speed work.
A live shared view now has snapshot semantics across an owner move, reassignment, or
mut call. Talk keeps the old storage alive for the view while the owner proceeds with its
new value. Shared loans therefore do not block ordinary mutation; copy-on-write preserves the reader's
picture.
The rule reaches storage too. Tuple elements, enum payloads, struct and heap fields, and global slots own the references stored in them, even when their declared shape contains a borrow. A local bare borrow remains a frame loan. This distinction lets stored iterators and borrow-carrying values survive replacement without dangling.
One deliberate edge remains: returning a bare &T rooted in a named value owned by the
current function is rejected, because the borrow cannot carry that ownership out without taxing every
borrow-returning call. Declaration-invalid borrow fields, live &mut conflicts, linear
misuse, and unsafe memory operations outside core or a // unsafe source also remain errors.
A shared view remembers the value you saw, not the mutation that came later.- The Memory Desk
talk check now builds the backend's MIR far enough to run ownership
analysis, exclusivity checks, and the unsafe-source gate without lowering or executing. It checks every
declaration rather than only the entry point's reachable functions, and reports source-located errors
through the existing text and JSON diagnostic formats.
The command also reuses source text it already read, so talk check - no longer consumes
stdin once for frontend checks and then ownership-checks an empty program. A program rejected by
talk run now has a matching static-check path.
The execution stack was rebuilt around one deep compiler boundary: typed frontend output becomes source-level MIR, whole-program specialized code, and then register bytecode for the runtime VM. Script runs, package binaries, Talk tests, the C and Swift APIs, and the Wasm embedding all use that compile-and-execute road instead of maintaining separate meanings for the language.
The command line exposes the road directly. talk mir shows pre-allocation MIR,
talk bytecode renders final VM instructions, talk build FILE -o IMAGE writes
an image, and talk run-image IMAGE validates and executes it. Image decoding now rejects
impossible section counts, out-of-range control-flow targets, and empty switches before execution or
oversized allocation.
This is a full-language road, not a scalar demo. The rebuilt path executes record patterns and destructuring, mutable captured variables through shared cells, inferred recursive generics, derived equality and display bodies, dynamic protocol calls, heap regions, and resumable effects. Effectful closures capture the handlers visible where the closure is created, while imported files initialize before their importers in stable source order.
talk test /path/to/project now walks up to the enclosing package
manifest, so package:: imports and locked dependencies resolve exactly as they do when
testing from inside the project. Package runs honor --entry, and an explicitly named entry
must be a public zero-parameter function rather than a private implementation detail.
The C API now compiles a supplied document from its supplied path, restoring sibling relative imports
and useful diagnostic filenames. Mutable receivers and mut parameters also carry their
final values back through projected places and dynamic dispatch, closing cases where a successful call
had silently discarded the update.
The release gates run the core Talk suites, all 225 talk-syntax tests, talk-html, frozen examples, reference clusters for effects, strings, collections, drops, and ownership rules, plus eight benchmark archetypes with exact output and allocation-balance checks. CI now builds and tests the whole Cargo workspace and all targets, including the rewritten runtime and embedding crates.
The result is a large rewrite with a smaller user burden: shareable values behave like values, views keep snapshots, ownership errors show up before execution, and the VM does substantially less work to honor those promises.