I come from a Swift/Kotlin background and I've been learning Rust for fun in my spare time
From what I heard online I was expecting it to be a lot harder to understand!
The moving/borrowing/stack/heap stuff isn't simple by any means, and I'm sure as I go it will get even harder, but it's just not as daunting as I'd expected
It helps that I love compiler errors and Rust is full of them :D Every error the compiler catches is an error my QA/users don't
The language and associated tooling keep improving.
Over the course of the last decade I've made several attempts to learn Rust, but was always frustrated with having code that reasonably should compile, but didn't and I had to run the build to even find that out.
Now we have rust-analyzer and non-lexical lifetimes, both tremendously improving the overall experience.
I still don't enjoy the fact that borrows are at the struct level, so you can't just borrow one field (there's even a discussion on that somewhere in Rust's) repo, but I can work around that.
To drive the point home: I'm a frontend developer. This is a very different environment compared to what I'm used to, yet I can be productive in it, even if at a slower pace in comparison.
Rust is not the most productive language by any means... it is hardened AF if you avoid unsafe, but productive?
I can code much faster in almost any language compared to Rust. It creates mental overhead. For example, to compare it to siblings, Swift and C++ (yes, even C++, but with a bit of knowledge of good practices) lets you produce stuff more easily than Rust.
It is just that Rust, compared to C++, comes extra-hardened. But now go get refactor your Rust code if you started to add lifetimes around... things get coupled quickly. It is particularly good at hardening and particularly bad at prototyping.
They seem to be the opposite in the absence of borrowing without a garbage collector, since you need to mark the lifetime in some way.
Rust is not that bad at prototyping, you need to use the right featureset when writing quick prototype code. Don't use lifetimes, use clone() and Rc/Arc freely to get around borrow-checker issues. Use .unwrap() or .expect("etc.") whenever you're not sure how to pass an error back to the caller. Experiment with the "Any" trait for dynamic typing and downcasts, etc. The final code will still be very high-performance for prototype code, and you can use the added boilerplate to guide a refactoring into a "proper" implementation once the design stabilizes.
In fact, most of the time, I would favor styles like this even for not prototyping.
At the end, refactoring is also something natural. I would reserve lifetimes for the very obvious cases wirh controlled propagation or for performance-sensitve spots.
> It helps that I love compiler errors and Rust is full of them :D Every error the compiler catches is an error my QA/users don't
amen! I despise Python even though I used to love it, and that's because it's full of runtime errors and unchecked exceptions. The very instant I learned more strongly typed languages, I decided never to go back.
And then comes the point, where you get a scenario, which is actually, you'd think, at least, something simple, but then gets really tough to express in strongly, statically typed languages, and you might take a step back and consider for a moment, how simple it would be to express this in a language like Python, while still being memory safe.
Statically typing things is great, and I enjoy it too, when it is practical, but I don't enjoy it, when it becomes more complicated than the actual thing I want to express, due to how the type system of that particular language or third party tool (in Python) works.
From what I heard online I was expecting it to be a lot harder to understand!
The moving/borrowing/stack/heap stuff isn't simple by any means, and I'm sure as I go it will get even harder, but it's just not as daunting as I'd expected
It helps that I love compiler errors and Rust is full of them :D Every error the compiler catches is an error my QA/users don't