> These "big idea languages" tend to assert a kind of "programming ideology" over reality, and tend to, in my opinion, distance you from the thing you are trying to do, often, they claim, "for your own good" ... "You want to give HOW many objects a mutable reference to this value?" complains the Rust compiler. "Are you insane? You are a Rustacean, you don't do that kind of thing!"
I agree with the spirit of this line of thought: in general I favor pragmatism over zealotry, and I think it should be up to the programmer to determine how a tool should be used, not the tool itself.
However when we talk about something like the safety constraints imposed by Rust, it's more about citizenship than it is about the compiler being overly opinionated. By baking those constraints into the language, I can have confidence when I use third party code that it reaches at least some standard in terms of memory safety and thread safety. Much in the same way as a strict type system, those constraints free me up to not have to think about certain types of issues.
If I am writing code which only I will consume, I'm also free to use escape hatches to sidestep these constraints when I know they're not relevant.
I've written tens of thousands of lines of Rust by now, and I'm still not convinced the Rust model is the right one in terms of achieving its goals, but I think the approach is "reality based" with respect to avoiding some of the problems which can occur while developing software in collaboration with others.
In my view it's very pragmatic to leave dealing with ownership to the compiler. It's something that you have to deal with in any language (even if you have a GC) if you want to write correct code, but it's not something most programmers truly prioritize most of the time. Even those who do think about ownership can't get it right 100% of the time because they're human and get tired. Keeping track of any kind of state is a constant drain on mental resources.
Therefore, having the compiler deal with ownership correctly most of the time and maybe get in my way a bit some of the time when it's actually wrong (most of the time it isn't) is a tradeoff I'm happy to make.
For languages that have explicit memory management and concurrency (e.g. Rust) having compiler tracking of ownership, or equivalent, is an absolute necessity in the modern world.
But I'd argue most languages don't need ownership. GC is fine. Most of the problems we deal with in commercial software development are succinctly expressed in GC'd languages, and the benefit of using a language that explicitly tracks ownership is greater performance from being able to be closer to the metal.
You need ownership tracking even in languages with GC because you will be dealing with resources that are more than just memory, and with those GC isn't really enough. A GC alone doesn't really help you deal with concurrent access, either. If you don't have a borrow checker, you will be essentially doing the same work manually as you're reading and writing code.
Rust's ownership tracking is not only about memory safety. It can also help you with other kinds of resources whose ownership you can encode using the type system.
Yes indeed, I'd like it if other languages had ownership and borrowing. Hell, I'd like it if a language could actually achieve linear types without holes or being completely unusable.
They could allow more relaxed GC'd normal types, whether default or opt-in, but affine and linear typing are genuinely useful properties fo reasoning about code, from both correctness and performance perspectives.
One needs to look no further than the string slicing problem for that to be clear. It's not an issue in Rust, but in every GC'd language you have to pick between:
1. eagerly copying the slice, which incurs additional often unnecessary CPU and memory costs, but avoids
2. every substring operation which isn't defensively copied being a potential memory leak as you're slicing 3 characters off of a 5MB string on every HTTP request and storing that in a global map, which turns out to store the entire 5MB string you got it from
Or some even more complicated magic where you only perform the copy if the substring escapes, at which point your performance and memory characteristics become wildly unstable and the mere act of extracting a function can bring the entire system to its knees.
I'm working on this: https://github.com/austral/austral/
The idea is to start with a simple, easily understood linear type system and then add borrowing, but without going too far in the direction where the type checker becomes a tower of heuristics and conveniences so that programmers can write normal-seeming code which magically typechecks.
So you can learn how to write linear code from reading a set of linearity rules, rather than from trial-and-error against the linearity checker.