That "protection" seems pretty worthless to me, since a non-trivial number of the use-after-free bugs I've seen are triggered only in rare cases, which means you're still crashing in prod.
Overall, Rust's lifetimes are sometimes hard, but generally only when memory safety is also hard. Inko's docs claim it makes it easier to implement self-referential data structures without unsafe/raw pointers, but to be honest the references here don't seem significantly safer than raw pointers.
[1] https://docs.inko-lang.org/manual/latest/getting-started/mem...
But there are still some warts around e.g. generic async functions, where you do sometimes need to think very hard about lifetimes and know plenty of tricks. Arguably those are situations where memory management is hard, but it's not something that e.g. TypeScript, C#, Swift or Scala would make you think about.
The feedback (from Rust devs, at least) on this language seems to boil down to "But why isn't it Rust?", which also seems to be kind of a resounding sentiment around many different languages that Are Not Rust. Conversations around Zig and Go get derailed (by Rust devs) all the time.
So my question is, if a language Is Not Rust, and ultimately your demand is to use Rust, why even bother complaining? Just use Rust. The rest of us don't want Rust, so languages in this space (this space being defined as "Statically typed, compiled languages that Are Not Rust"), can be interesting. Derailing to poke at all the ways a language isn't Rust is just a waste of everybody's time.
As for comparisons to actual Rust programs: I haven't done any side-by-side comparisons, mainly because I worry they may come across as a bit disingenuous, as you'd never pick examples that make your language look worse than whatever language you're comparing to.
I'm sure a lot of people just roll out of bed and naturally dance with the borrow checker like it's an old friend, but to me it's an hindrance. Maybe because I don't just only do Rust. I do plenty of other languages, or my brain is inferior, or both.
Using Rust for non-pref-critical web apps is a nice exercise, and yields a super fast and efficient app. But in that case the mental overhead is not worth it compared to a language and developer experience like Kotlin.
- if you pass it is a parameter, pass a read-only reference.
- if you return a value as a result of a function call, clone as necessary and return as an owned object, try to never return a reference.
- if the above two don’t fit, it’s thinking time; either the structure of the program can still afford for them with some refactor, or it’s genuinely incompatible.
The former avoids excessive copying and limits the bugs due to attempting to modify a cloned object, the latter limits the lifetime managing gymnastics required. The third allows to keep the program logic relatively simple except in the cases where it’s really required.
Hope that this is of some use :-)
Completely breaks with a lot of async code