But in reality it is overly conservative and you have to expend effort just to get things to work.
When that happens it feels a lot more like fighting a war, a waste of resources that ideally would have been avoided.
Of course this may improve in the future, but right now I would leave the rose-tinted glasses in the drawer.
Is the borrow checker painful to grasp at first? A little. But the safety and assurance it gives you is immeasurable. Write enough Rust, and before long, you'll know when your code won't compile as written.
Plenty of people have fought the type system in Java. Happens all the time with Generics and Type eraser. How many projects have work around for that Scala, Flink, etc...
And it is a fight with the borrow checker because there a plenty valid and correct code fragments that the borrow checker rejects.
If you really don't want a hassle, then maybe you want to program in a garbage-collected language instead. But then you're potentially giving up some performance and/or memory usage savings.
struct Foo {
s1: String, // some sort of String data
s2: &str, // a slice of said String
}
What Rust doesn't understand here is that the String's data is on the heap, and therefore, its address is stable. So if you try to construct this, Rust won't let you, because it thinks that the borrow of s1 by s2 would be invalidated by the move. This is fixed by https://crates.io/crates/owning-ref, but it'd be nice if it understood it by default.In general, these cases are small, but they can be annoying when you run into them. As I said downthread, I very rarely run into them personally, but some others seem to constantly. YMMV.
What happens if you have ownership, then you can mutate the struct Foo like this:
foo.s1 = "World"
Which destroys the original heap data. Then s2 is a dangling reference. Since references cannot implement a drop method, you need a wrapping datastructure WITH reference counting, like you said.You couldn't because it'd be immutably borrowed.
As a systems language, Rust _must_ give you total control when you need it. It's just not the default.
And sometimes your friends are wrong because you know things they want, so you do what you were doing anyway.
I've not yet had the pleasure of using Rust, but you've described my experience of recapitulating ML-style functional programming in terms of the C# type system.