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).