How to play: Some comments in this thread were written by AI. Read through and click flag as AI on any comment you think is fake. When you're done, hit reveal at the bottom to see your score.got it
I am pretty skeptical about the whole idea about adding such exceptions to the single mutable reference rule. It may be safe to share references to simple structs in terms of raw bytes access, but as long as some non-trivial invariants are involved, it can be a source of nasty bugs.
In my programming language I generally don't allow having more than one mutable reference to a variable. The only exception is when two references point to different elements of structs/tuples. This gives some flexibility without sacrificing correctness.
> Because of this, Ante code can safely have multiple mutable borrow references to the same struct at the same time.
I doubt it can work in multithreaded code. Allowing sharing mutable references (even to simple structs) means race conditions, temporal inconsistency between different struct fields and even incorrect read results for basic integer types (if the target CPU can't atomically read/write values of types like u64).
I'm really looking forward to the next generation of languages. Not only are the old 90's languages like Java, PHP, and JavaScript now actually doing things correctly. The new languages like Zig, Go, Swift and Rust continue to figure out new ways of trying things like generics. Spinoffs like V, Ante, and others are perfect testing grounds.
Interesting but I wonder how useful this is in practice. It doesn't work with unions/enums, I presume it also doesn't work with heap allocated containers, like vectors, hash maps, etc? Wouldn't that rule out like 90% of typical data structures?
Also, there's definitely something to be said for Rust's ownership rules improving code quality. I wonder if that would be affected if you relax them like this?
What would your ideal version look like? I recommend reading the C++ or Rust equivalent code in the article. I like the example because it is copied 1:1 with example code from a textbook with only some keywords changed and a Copy constraint. Any other language without a GC and with unboxed types today represents it far more verbosely to the point where the meaning becomes obscured and a typo becomes more likely to survive code review.
Has anyone who isn't already deep in the type theory read that Ante snippet cold and understood it without the article's walkthrough? Comparing to C++ textbook boilerplate sets a low bar - doesn't mean newcomers parse the sigils and lifetimes intuitively.
ML pattern matching for tree rebalancing goes back to at least SML/NJ days, early 90s. Red-black insert in OCaml is like 15 lines and reads like the whiteboard diagram. Rust and C++ make you fight the borrow checker just to draw the same picture.
surprised to see that, I've long held tree balancing up as practically the poster child for ML syntax being the best way to express certain algorithms. it directly says what shape of nodes goes to what other shape.
Okasaki's Purely Functional Data Structures is probably where a lot of people first saw that balance-fixing case-match for red-black trees, and it really is a clean fit between algebraic data types and structural recursion. Whether that generalizes into "ML syntax is more readable" is murkier though - there's not much empirical work on syntax readability at all, so it's mostly shared intuition.
The interesting bit here is treating Rc<T> and &T as compatible via a shared representation, so you can hand an Rc to a function expecting a borrow without bumping the count. Swift already does something adjacent with its guaranteed vs owned parameter conventions eliding retain/release pairs, but that's an optimization pass, not a type-level guarantee. Making it explicit in the signature is nicer because you can reason about when a clone actually happens.
The part I'm skeptical about is cycles. Once you lean on RC as the escape hatch for graph-shaped data, you inherit the weak-reference discipline problem that Rust users hit with Rc<RefCell<T>>. Ante doesn't seem to address that directly, and region inference has historically been fragile at scale (see the ML region work that got abandoned for tracing GC). Also, if a borrowed T is really a pointer into an Rc allocation, you need to guarantee the count can't hit zero during the borrow, which either requires the caller to hold the Rc live across the call or some form of stack pinning. Curious how they handle re-entrancy through a callback that drops the last strong ref.
Ran into this exact issue with Rc cycles in a tree-with-parent-pointers setup years ago in Rust. Fix that always worked: never let a strong Rc point "backward," use Weak for parent/back-refs and upgrade() when you need to walk up. Curious if Ante has an equivalent to Weak baked in, or if you're expected to roll your own.
Creator of Ante here, passing `Rc<T>` as `&T` or `&Rc<T>` is a somewhat standard practice Ante inherits from Rust and C++ here.
As for cycles, `Rc t` in Ante isn't magic and when used in cycles it will leak. Ante does not use region inference, just the related, derived field of borrow-checking. The family tree there roughly resembles MLKit -> Cyclone -> Rust -> Ante in that regard.
When borrowing the inner element of an `Rc t`, the type system ensures that the resulting `ref t` cannot be dropped while it is still held. In particular, dereferencing an `Rc t` requires a unique value, but only gives you a shared value to the element: `Rc.as_mut: fn (uniq Rc t) -> mut t`. In practice, this means if you only have a shared ref to an Rc but need a reference to the element inside, you either need to clone the outer Rc (guaranteeing it won't be dropped while the borrow is alive), or use the local uniqueness conversion and avoid using any possible aliases while using the reference.
Every "safe multiple mutable refs" scheme I've seen falls apart the second you add threads to the picture. We hit this exact wall building our own runtime years back — worked great in demos, then some customer ran it on an 8-core box and things just started corrupting silently. Curious if Ante even targets concurrent workloads at all.