I'm learning Rust because it seems clear that it's going to be important professionally. I wish I loved it, I really do. I see the benefits. But, at least so far, it's one of the most unpleasant languages I've used. I keep hoping that as I gain proficiency, I'll stop disliking it, but as I climb higher on the learning curve, I'm not really warming to it.
It's fine. It won't be the only language I'll be proficient in while being averse to it at the same time. But I heard so many people proclaiming their love for it that I expected to enjoy it, too.
As a counter example, I love programming in Rust. Fighting the borrow checker ended a long time ago. Even the errors are rare these days, except in cases I trigger them in order to examine the types. Rust compiler also seems to have improved in accepting broader cases that are valid.
For me, the key to understanding the borrow checker was understanding the underlying memory model. Rust memory model is the same as that of C, with some extensions for abstractions like generics. The borrow checker rules seem arbitrary at first. But it's deeply correlated to this memory model. The real value of the borrow checker is when I trigger it unintentionally. Those are bugs that I made due to lapse in attention. What scares me is that another language like C or C++ might simply accept it and proceed.
Yet another pleasant side effect of Rust's strict type system and borrow checker is that they gently nudge you to properly structure your code. I can say for certain that Rust has improved my code design in all the languages that I use.
My experience is that most programs dealing with ordinary problems don't need such complicated data structures. In cases you do, Rust has a few options:
1. Use Rust's runtime safety checks, using Rc, Weak, RefCell, etc. It will be as ergonomic as GC'ed languages (no productivity loss). While this has a runtime performance penalty, it will still be mostly comparable to other languages. This works for most use cases.
2. If you need the last ounce of performance, just drop all automated safety checks and do it manually using unsafe. Even if you make a mistake, your debugging will be limited to the unsafe blocks. This approach isn't unusual in Rust.
3. Use either the standard library or something on crates.io that does what's given in 2. Rust's generics make it easy.
1. Option 1 quickly degrades into unrefactorable mess of TypedArenas, nested Rc<RefCell>>, lifetime annotations everywhere, and the like. It is unmanageable, which is why even libraries like PetGraph do not use it.
2. No, I don't need every last bit of performance. C++ performance is OK. Or any other sane language like Nim, Crystal, etc. I need async, though, which is yet another hell in Rust.
3. This absolutely can't be done with standard library. There are libraries like PetGraph, which solve this particular problem (by some very unobvious approaches and bits of unsafe code), but there are many problems like it which don't have any libraries for it yet.
I do have hard problems. I want a language which makes hard problems easy, and impossible problems hard. Rust is definitely _not_ such a language, and it makes me like 5 times less productive, and sucks all joy out of programming.
Use one of the many libraries that have safe abstractions over unsafe code? I don't know why people think you need to roll your own? I guess that's just what people do in c/c++, doesn't seem very productive...
There are definitely no less libraries for C++. I am a scientific software engineer, and occasionally I do develop new things. And Rust makes writing new system-level software way harder, which I don't understand, as it is a system-level language.
The lack of default/named function arguments is what still gets me. It's such an absolute basic programmer ergonomics feature shared by most popular languages; even C++ has had defaults since forever.
It would have been nice for Rust to have Default/named/optional function arguments because the proliferation of slightly differently named functions that do the same thing would go away.
Good question! There's no single thing, I think, and the things I dislike about it aren't even really technical criticism or the like. They're more... aesthetic? I find the syntax unpleasant, for instance. It's extremely opinionated and a few of those opinions are ones I disagree with.
Also, just generally, it tends to make even simple things pretty complex. I understand why and am not really objecting to that, but it does make using it a bit like running with lead shoes.
I expect that the latter part may get better as I use it more (but perhaps not -- there are other languages I'm fully competent in but dislike for similar reasons).
I share your sentiment about Rust. Fine language for sure, I just don't enjoy programming in it. Simply put, I don't like using the abstractions that the language encourages.
For what it is worth, I found pursuing Zig to be a breath of fresh air. It's a promising alternative in the same space as C (and also Cpp and Rust). Checkout Andrew Kelley's introduction to the language.
There are a few, and they aren't something that I can't live with, of course. A great example of the sorts of things I'm talking about are Rust's insistence on camel case and snake case.
It's fine. It won't be the only language I'll be proficient in while being averse to it at the same time. But I heard so many people proclaiming their love for it that I expected to enjoy it, too.