6/30/2026 at 11:57:29 PM
I can see how multiple mutable references is fine in a single-threaded context, but surely this would cause UB in the multi-thread context?by hingler36
7/1/2026 at 12:42:34 AM
Creator of Ante here, Ante inherits Rust's Send/Sync for thread-safety. `mut` refs and `Rc` which provides shared mutability don't implement either and thus can't be shared across threads. So shared mutability is only within a single thread.by jfecher
7/1/2026 at 7:26:22 AM
OOI why did you go with RC at the lattice bottom rather than generational refs? Not sure how in touch you are with the author of Vale?What would be good is if effects are used to discharge the ownership obligations, that should dovetail well in Ante. BTW I appreciate the clear effects handling in Ante, very nice!
by alexisread
7/1/2026 at 9:51:30 AM
> Not sure how in touch you are with the author of Vale?FYI - this article is written by the author of Vale
by nu11ptr
7/1/2026 at 12:20:41 AM
Given their "shape stability" design, not necessarily. The three ways that multithreaded access can cause UB are:* changing the type of the underlying memory (e.g. because it's part of an enum variant and you changed the tag, or because you changed the length of a vector) * data races (can be defined away by making [effectively] every access Relaxed, as Java does * use after free (resolved here by reference counting)
In Rust, any type specified like this (all accesses are Relaxed, "shape stable", and reference counted) can already be used in safe code using & references. In theory. But the first property (forcing all accesses to be Relaxed) is very annoying to achieve for arbitrary user data types--even if those types are Copy or other kinds of plain old data--which is a problem e.g. for specifying stuff like sequence locking. The example they give here with bare unions is also very annoying to use in Rust even though this mode of use is safe, because the type system doesn't track which variant is active. So I definitely think there's room to innovate ergonomically here.
(It does seem from the text like this is intended for a single-threaded context, where I think the arguments against Cell are a little less persuasive, but it's still true that it's very awkward to try to figure out how to safely project a Cell down to the exact fields you need to mutate, even though something like LambdaRust will tell you it's safe to do so).
By accepting semantics like this you are, of course, opting out of a lot of potential optimizations around both shared and unique accesses, but you are already doing this in most langauges anyway, so if you're willing to eat the performance cost this can be quite acceptable. The bigger problem (briefly noted in the post) is that the kind of recursive analysis they're proposing doesn't necessarily compose well. Rust explicitly opted out of most types of analysis that can't be efficiently summarized at the function signature level to improve compilation speed. Historically, not being able to efficiently summarize functions that do this kind of stuff has been a big thing that killed attempts to automatically add borrow checking like facilities onto existing C++ code, too. But maybe a language designed for it from the ground up will avoid this problem.
by Jweb_Guru
7/1/2026 at 12:43:49 AM
I was thinking of the data race case, and I was unaware of relaxed access used by other languages. Thanks for sharing!by hingler36
7/1/2026 at 6:26:00 AM
Jake has already mentioned how the type system enforces single-threading (using similar mechanisms as Rc in Rust), but it's not necessarily the case that read-write races from multiple threads are UB.In particular, Java allows aggressive multithreaded access, and the memory model has some pretty strong guarantees. Informally stated, if a read and a write race, then the read is guaranteed to observe either the old or new value.
Go is something of a middle ground [1]. Races on simple scalar values are not UB, but "fat pointers" (slices and interfaces) can tear and can lead to "arbitrary memory corruption."
When I was reading about "stable shape" I was wondering if it might be something similar. You easily get the same UB problems when dealing with sum types, as a tear across tag and variant payload can cause all kinds of things to go wrong.
by raphlinus
7/1/2026 at 12:12:34 AM
Not if you define the behavior. Many programming languages have robust memory models ranging from "happens before" style systems like those in Java or Modern C++ to the Software Transactional Memory system in GHC/Haskell.Correct, shared mutation is an extremely well-understood problem in the sense that there are points in the programming language design space that admit it with present technology.
As always, there are tradeoffs.
by reinitctxoffset