Valen: References That Remember Where They Point
Translated by a model; the original is in Russian.
Evan Ovadia, author of the experimental language Valen (a successor to Vale), has published a walkthrough of a new memory-safety mechanism: so-called group borrowing. The idea originated with his colleague Nick Smith and was first meant for the Mojo language, where it didn't take root. After last year's write-up, Ovadia says the concept spread widely: it was adopted by Google's Carbon (which credited the original), as well as the Ante, Zeta and Fang languages.
The core idea
Classic borrow checkers, like Rust's, rest on the "shared-xor-mutable" rule: while you hold a reference to an object, nobody else may change it. That clashes with how we tend to write C++, where a single owner plus many plain pointers to it is routine. Group borrowing relaxes the rule down to a simpler "no use-after-free."
The machinery is built on the notion of a "path." Under single ownership every object has exactly one owner, and therefore one path — say world.entities[].hp. Each reference remembers the path of the object it points to. When an object is modified or destroyed, the compiler marks every reference pointing inside it as invalidated; using such a reference afterward is a compile error.
What it enables
The approach accepts patterns that trip up ordinary checkers: multiple local variables or parameters pointing at the same object, writing through any of them; the ScopeGuard pattern; several structs holding references to a common subsystem. Use-after-free errors are still caught at compile time, and with no run-time cost.
A key subtlety: a function declares in its signature which paths it mutates. A parameter like entity in world.entities[] mut means you may change only the elements inside world.entities, not the whole world. This strengthens API boundaries and, the author hopes, feeds the optimizer more precise information (which may require patching LLVM). Valen has only one kind of borrow reference, and mutability is decided by the function rather than the type.
Rust interop
Special care goes to calling into Rust. A Valen reference can be turned into a &mut temporarily if no other paths can reach the data, otherwise only into a &. And to know where a reference returned from Rust points, Valen adds "wildcard descendant paths" like in self.gem... — "somewhere inside self.gem."
This is the first of a planned series. Ovadia promises to cover later how reference counting and generational references can be blended into borrowing. Notably, the piece itself was written without AI: if you want people to read your text, he argues, write it by hand.
Source: Lobsters
Comments
Sign in, to comment.