> Tracing GC is the simplest model for the user, and helps with time management and development velocity, two very important aspects of software engineering.

> Borrow checking is very fast, and helps avoid data races.

One thing many people seem to assume is that not having to care about memory means you can program faster and get to your goal faster. As the author here seems to do. However as it turns out, if your program is more complex than a ~100-1000 lines of code, explaining in a explicit way who owns what and who gets to change state when, is a very useful way to avoid bugs.

Saoirse Shipwreckt aka withoutboats mentioned this a while ago in https://without.boats/hire-me/

> Rust works because it enables users to write in an imperative programming style, which is the mainstream style of programming that most users are familiar with, while avoiding to an impressive degree the kinds of bugs that imperative programming is notorious for. As I said once, pure functional programming is an ingenious trick to show you can code without mutation, but Rust is an even cleverer trick to show you can just have mutation.

and later follows up on this in https://without.boats/blog/revisiting-a-smaller-rust/

> I still think this is Rust’s “secret sauce” and it does mean what I said: the language would have to have ownership and borrowing. But what I’ve realized since is that there’s a very important distinction between the cases in which users want these semantics and the cases where they largely get in the way. This distinction is between types which represent resources and types which represent data.

I would love a language (or C++ subset!) where we could get the benefits of that secret sauce, while mitigating or avoiding some of its downsides.

Like Boats said, the borrow checker works really well with data, but not so well with resources. I'd also opine that it works well with data transformation but struggles with abstraction (both the good and bad kinds), works well with tree-shaped data but struggles with programs where the data has more intra-relationships (like GUIs and more complex games), and works well for imposing/upholding constraints but can struggle with prototyping and iterating.

These are a nice tradeoff already, but if we can design some paradigms that can harness the benefits without its particular struggles, that would be pretty stellar.

One promising meta-direction is to find ways to compose borrowing with mutable aliasing. Some promising approaches off the top of my head:

* Vale-style "region borrowing" [0] layered on top of a more flexible mutably-aliasing model, either involving single-threaded RC (like in Nim) or generational references (like in Vale).

* Forty2 [1] or Verona [2] isolation, which let us choose between arenas and GC for isolated subgraphs. Combining that with some annotations could be a real home run. I think Cone [3] was going in this direction for a while.

* Val's simplified borrowing (mutable value semantics [4]) combined with some form of mutable aliasing (like in the article!).

* Rust does this with its Rc/RefCell, though it doesn't compose with the borrow checker and RAII as well as it could, IMO.

[0] https://verdagon.dev/blog/zero-cost-borrowing-regions-part-1... (am author)

[1] http://forty2.is/

[2] https://github.com/microsoft/verona

[3] https://cone.jondgoodwin.com/

[4] https://www.jot.fm/issues/issue_2022_02/article2.pdf