Rust has a steeper learning curve than most languages but it also has a very beginner-friendly and welcoming community. So don't be scared, you can do it! If you get stuck on something it's always easy to get help.
I would say give Rust a go anyway. Worst case is you end up not getting along with it, best case is you now have a new tool to reach for.
That’s why lots of work has been done and still is being done to make that “work with the compiler’s help”.
The thing is: in _any_ programming language, whenever you pass anything mutable to another function, you have to think about ownership.
For the sake of reliability, rust makes that explicit, where other languages such as C and Java assume the programmers know what they are doing. To not make that too tedious for the programmer, rust also infers quite a few rules.
Rust is getting better on both fronts. Its ability to infer ownership grows, and it gets better at reporting problems it can’t solve on its own.
My original comment was a clumsy attempt to reassure ‘antpls and other Rust beginners that lifetime errors generally manifest as the less-troublesome kind on this scale.
I don't think "fighting the compiler" is a useful concept. No matter what language you're learning, you have to learn both the language's syntax and semantics.
If your program barfs up an error at runtime because you made a semantic error the language forbids, that's no better than barfing up an error at compile time because you made semantic error the language forbids.
So it's both more accurate and more precise to say that a language's semantics might be complicated or subtle, but the compilation step is orthogonal to the actual problem you're talking about.
Compile-time errors, on the other hand, ensure that the entire program meets some baseline of correctness before any of it is run. Neither is necessarily better or worse than the other, but they are categorically different things that have their own effects on the experience of writing programs.
If you are in the category of users that never RTFM, then I guess this article might be for you, but then kind of by definition, you won't read this article either, so...
---
For example, in C++ a generic `T` can only mean an owned type:
template<class T> void foo(T t);
template<class T> void bar(T& t);
You can't pass `foo` a reference to `T`, you'd need to pass it an owned type like `foo(std::ref(t))` instead or similar.In Rust, when you write
fn foo<T>(t: T);
you can call `foo` with an owned type or a reference, no problems, generic types are... well... generic.So if you start writing Rust code with a C++ background without reading the book, then you might probably think that generics in Rust work like templates in C++. One couldn't be more wrong about this, they are in fact completely different language features. They might solve very similar problems, but they are as different as Python is from Haskell.
Wrong.
template<class T>
void foo(T t) {
}
int main() {
int x = 0;
foo<int&>(x);
}
Unadorned Ts as function parameters will by default be deducted as value types, but a generic T parameter can represent references just fine. This is especially important for template classes.> you might probably think that generics in Rust work like templates in C++. One couldn't be more wrong about this, they are in fact completely different language features. They might solve very similar problems, but they are as different as Python is from Haskell.
it seems to me that they are more similar than different.
Indeed, thanks for the correction!
> it seems to me that they are more similar than different.
I think the Haskell vs Python comparison is accurate. Rust generics are strongly typed (definitions are checked), while C++ templates are "weakly" typed (type checked when they are instantiated). In C++ it is trivial to write templates that will never type check when instantiated, while in Rust this is impossible.
>Indeed, thanks for the correction!
Sorry for the brusque response, I had a "someone is wrong on the internet moment".
>Rust generics are strongly typed (definitions are checked), while C++ templates are "weakly" typed (type checked when they are instantiated).
True. The usual solution is to force-instantiate them against archetype classes. While it is not perfect it is a good approximation.
This is correct, but you not only need to make sure that they accept an archetype class, you also need to make sure that they reject all others.
This often requires writing and instantiating a substantial amount of code for testing purposes, which often ends up as large or larger than the actual logic itself.
I suppose you already know the pain of doing this, but for those who do not, it is like testing a function in python for all possible inputs. Can be done, but is a lot of work.
In practice, most generic C++ code is not tested in this way due to how painful it is to do so.
So what in Rust takes no work, takes a huge amount of effort in C++.
But a lot of it is UNLEARN. Before, I was doing mostly F# and believe back then I was a very functional developer, but now with rust I do more functional programming than before.
Most of time, errors and problems show up because rust is trying to put you towards a way to design the code. The most you fight it, the harder is.
I think, 90% of time rust is right. Doing ERP-like work I say rust is even more productive than F#, that was also great to me.
--
Rust get truly hard when try to do pseudo OO, trying to do introspection (the harder stuff I think), and mix mutability inside the same struct. But most of that happend outside regular development (I'm building a toy lang and hit the hard stuff often)
And the Rust developers indeed deserve respect in my opinion too. They are trying to solve a hard problem and not taking the worse-is-better-option.
I use rust and I don't worry about the lifetime stuff. Just hack away and get the job done. Overall, rust is lower startup friction than most of the tools I use (though YMMV).
And even if you did gain a misconception, so what, apparently you'd just be joining other people writing rust who share the same one.
If you come from C/C++ then all the notions discussed should be familiar to you, because you used to do the borrowing and lifetime management manually, or you were doing something really wrong. :)
Whereas the rust compiler helps you with all this (super hard and annoying) stuff.
In reality, though, while it took me a while to get relatively comfortable with the borrow checker (much longer than I expected as an old school C++ programmer), 99.9% of the time it works exactly as I expect. Of course the other 0.1% of the time takes a lot of my energy ;-)