Four limitations of Rust's borrow checker
Learning curve and developer experience
- Many describe Rust’s borrow checker as initially painful: small refactors can explode into large changes, especially with closures, async, lifetimes, and threads.
- Some argue that after months of use, it “clicks”: you learn to structure code so the compiler is satisfied up front, and refactors become smoother.
- Others contend this is giving up on incremental development: if a tiny spec change forces major restructuring, Rust feels hostile or “not fun” for evolving systems.
Borrow checker limitations and workarounds
- Several limitations in the article are seen as real but niche; common workarounds include:
- Cloning more liberally instead of threading references everywhere.
- Using Arc/Rc + Mutex/RefCell for shared or cyclic structures.
- Using arenas, SlotMap/Slab, generational arenas, or ECS-style layouts instead of complex pointer graphs.
- “Command pattern” or restructuring APIs so mutations happen where a single mutable borrow is available.
- Critics argue that some safe patterns (e.g., conditional borrows, back-references, scoped async tasks, partial borrows of structs) are unnecessarily blocked, forcing contorted designs or indirections.
Indices, arenas, and safety tradeoffs
- A big subthread debates “indices instead of references”: storing objects in Vecs and passing integer IDs.
- Supporters: this often plays nicely with the borrow checker, can match CPU/cache behavior well, is easy to serialize, and underpins ECS and generational arenas.
- Critics: this is “unsafe code without the unsafe keyword,” reintroducing use-after-free–like logic bugs (e.g., stale IDs reused for new objects), undermining Rust’s practical safety unless paired with robust allocators (generational arenas, SlotMap).
Safety vs correctness and language choice
- Multiple comments emphasize Rust’s notion of “safe” = no UB, buffer overflows, data races; logical and application-level security bugs remain possible.
- Some feel Rust is best reserved for systems/low-level work and that most general-purpose code should use GC’d languages with simpler mental models.
- Others report that Rust’s constraints improve design in any language by encouraging message passing, immutability, and less shared state.
Future improvements and tooling
- Commenters point to ongoing work: Polonius for more precise borrow checking, async closures to fix some async/FnMut issues, and better Send analysis.
- Tooling like rust-analyzer refactors is seen as lagging behind richer ecosystems (e.g., JetBrains/Resharper).