That said, I am curious why different people have these different feelings. One aspect is likely rooted in the fact all of our brains are different. But I also wonder if first impressions play a big role here. A good example of a cryptic rust error is the `expected type Foo, but found type Foo` error message which is very inscrutable, especially to a new users. There are also some lifetime errors that can be hard to understand.
I wonder if someone encounters these type of messages very early on in their learning experiences, the unpleasantness of having to decipher them colors the rest of their learning experiences.
Path dependency has big impact on what seems natural, intuitive, etc. Part of that is what you've done before, and part is first impressions, and part of it is your approach to learning (or the approach taking to teaching you) the subject at hand.
I’ve approached Rust via different books and tutorials before and come up with the “it’s awesome, but too hard” feeling and set it aside.
Recently I've been trying Hands-on Rust [0] and going off to the side from it and Rust is clicking pretty well. Not sure if the book is a better fit for me, if the past false starts have prepared the ground, or what specifically changed.
So much this. One example I hit a lot is when people keep saying “async/await is too hard, green threads are much more intuitive”: coming from a JavaScript background I feel async/await and all the future combinators much more intuitive than dealing with threads and channels. Before async rust was stabilized I had to learn how to use threads and I was always frustrated how clunky it felt, and now that Rust has async/await I use it for everything IO related, because to me it's just much more familiar.
Does Rust actually give an error like `expected type Foo, but found type Foo`, as in both types are the same in the error? I don't think I've seen that before, but I don't write much Rust.
If both types are the same, what does the error mean?
To anyone who gets a cryptic error message - that's a bug, report it.
On the other hand, if you're fine with a garbage collector, which most people are most of the time, then Go is going to feel more natural. For some people, Go is more comparable to Python than Rust, because of this one big difference.
In fairness, I have found the compiler errors to be extremely helpful. They often tell me exactly what to fix. But honestly, they shouldn't have to do that. The syntax should have been obvious from the beginning, as it is in most programming languages.
type TestResult = Result<(), Box<dyn std::error::Error>>
is not obvious nor simple and makes a joke of the claim that Rust is simpler than C++ in error handling. Damn, I prefer straightforward C++ exceptions after seeing stuff like this.Someone who has never thought about that stuff must surely find it harder to appreciate Rust.
That hasn't been the case for years. The 2018 edition officially stabilized Non-Lexical Lifetimes, allowing tons of valid programs to work. There have been a lot of other improvements since then to address papercuts.
At this point Rust is a pretty easy language to learn imo.
Over the years the following C++ aspects have and continue to drive me nuts. On a scale of (Sarcasm coming next) 10:
* (7/10) build time, and dependency management with the 81 million tools, formats, approaches to deal with this.
* (1/10) 21 page error sets resulting from single word typos in templated code: even Egyptologists ask how do we put up with that? At least we have nice rocks to look at. Yah, they have rocks. How come we don't have rocks?
* (1/10) Code decl duplication between .h/.cpp
* (1/10) Long, pointless C++ errors. if you have an orthodox background the guilt trip C++ lays on for mismatched function calls is legion; you really feel it. It tells you such-n-such function could not be matched ... but look at the 42 million function calls you could have made ... should have made ... and it's killing me you didn't make; you seeing the effort I'm putting into this? It's killing me ... I just need the cop to say it straight: you screwed up. Ticket. See in court. Have a nice day. I prefer one liners.
I'm in no rush to waste time on Rust. I'd rather stick to GO where I can, Zig when I can. At the office we're 65% C++, 25% C. Stack overflows, memory corruptions do occur periodically; I've sorted several of those out. But the new code is C++ which makes heavy use of STL. Much better. There is growing adoption in GO and Rust, but the vast amount of C/C++ code means the apple will not fall too far from the tree.
So, it's quite possible for various people to feel more comfortable using Golang than Rust, and the opposite can be true as well, where using Rust is preferred over Golang. At the end of the day, it will usually come down to individual or corporate priorities.
Another of the newer languages that fall into a similar usage space would be Vlang (https://github.com/vlang/v). It being debatably easier to learn and use, in the context of languages that more easily interact with C.
[...]
> The syntax seems overcomplicated, the compiler errors are cryptic, the IDE is not helpful.
Yes, Rust is hard to learn. Rust does _seem_ over-complicated.
However I like to compare Rust to exercise. You need to do a bit of it before you start reaping the benefits of it.
If you suspend your judgement for a bit and try to write some Rust, starting from the very beginning you will find that:
- Rust is actually a small language at its core, unlike the monstrosity that is C++ . You don't really need Advanced Rust to be productive. Use Advanced Rust only when you're... advanced
- Rust actually is very consistent
- The Rust compiler is actually very helpful. It's the least cryptic compiler I've met. But its OK if you feel that now as you're just beginning your journey with Rust
Avoid the temptation to "read" Rust from a book. Try to _do_ Rust. Otherwise it might overwhelm you. Simply keep adding Rust techniques to your arsenal as you mature in your usage of Rust.
Learning Rust changed the way I look at programing. Rust is a beautiful language. As a random example, just look at the the Firecracker VMM written in Rust -- https://github.com/firecracker-microvm/firecracker . It would have been able to very difficult for me to understand the codebase if it were written in C/C++!
Rust is one of those rare languages I've encountered that if the code compiles, there is a high probability it will work. The type system is that good!
TL;DR Persist and you will reap the rewards with Rust.
I find rust and modern C++ codebases equally hard to understand. How can you be so sure that the reason you find it easier to understand is not simply because you know rust better than C or C++?
Perhaps the problem was that I was overconfident and immediately started with pretty advanced Rust - writing a web assembly that performs big data analysis using the "polars" library.
The problem with Rust is that to write good Rust, you need to accept that you can't use the same approach to solve a problem you could use in other languages. The borrow checker and its implications aren't necessarily difficult, but they're different.
I'd compare the experience to someone who started in Python learning Haskell for the first time: it can take weeks or more before one can truly understand a monad. If you start with basic functional programming you can be quite productive before you need such code structures, but when you open a code base where monads are mixed liberally, your head will be spinning.
Rust may be a lot closer to traditional imperative languages, but the implications of the safety mechanisms in the language are something you can't just skip over. It'll take time and practice to write code that the Rust compiler likes.
If you're getting started, I'd recommend writing some toy programs for the CLI instead. I also recommend using "clippy" to warn you of code smells (it'll suggest improvements when it can!) and to get links to specific problems you might not be aware of. As for the IDE, I recommend the rust-analyser plugin over the native "Rust" plugins found in most IDEs, because the basic ones fail to do proper macro expansion and leave you guessing on how to use libraries.
What would be an alternative if I plan to develop a high-performant data analysis tool for WASM(similar to Perspective[0])? I looked at the list of supported languages[1] and Rust seems to be a good choice.
It has to be said that I have many (mostly subjective) problems with the Go language and the ecosystem, but with the help of GoLand I was productive in minutes. The layer for exchanging arguments between the browser and the "native" code is a bit weird, but once you get passed that, it's easy to get going.
The Rust problem with WASM is more about learning Rust well and picking the right libraries (many of them have dependencies that don't work well in the browser!). Setting up tools like cargo to compile usable WASM files also takes a little practice, but that's at most an afternoon of messing around before you should be reasonably comfortable with it. In my opinion, the main improvements Rust brings to the table are the (memory) security features and the fearless multithreading, but neither of them are of much use within the WASM runtime. The borrow checker will still help you write correct code, but it can be an unnecessary pain in the ass when it doesn't need to be. Rust is a great systems programming language, but I'm not so sure about it becoming the de-facto WASM standard.
Of course, if you already know Rust, or know a library that would be super useful to you, it's great that Rust can Just Work (TM) with the right setup. First-party tooling support is pretty great for a language to have!
If I had to choose, I think I'd pick a language that I'm comfortable with (C#, Kotlin, Java) and has the necessary libraries easily available, and see if the tooling works well for my use cases.
I'm also watching Zig evolve with interest; it's not quite there yet, but it's integration with C libraries and some of its more modern language features are very promising. WASM code doesn't need many of the complexities modern languages bring, but older languages like C can lead to dangerous programming paradigms, so I think a mix between the two can produce clean, performant and fully-featured code. I wouldn't recommend it for production use yet, though, as the language is still in constant development with breaking changes between point releases!
I think it would be a challenge to compile all dependencies for a fully features C program into WASM, but if you pick your libraries well, C could be an excellent language for speeding up complex calculations in Javascript.
I've been watching the videos by Andreas King on SerenityOS and the code is so clean that at first I wondered what programming language I was even looking at. I see the SerenityOS codebase as proof that if C++ programmers wanted to write modern, elegant, readable code, they definitely could.
In practice, though, most C++ programs are full of legacy code or are written by people who don't necessarily know about or agree with modern ways to program C++. It's easy to write beautiful code if you also wrote the memory manager and standard library in modern C++, but most people don't have that luxury.
By being created with a more modern standard library, Rust has an advantage over C++. There is no legacy code to remain compatible with and there is no real way to write "old-fashioned" Rust because the project hasn't existed for long enough. I've seen plenty of terrible, ugly Rust, most of it in my own personal projects. The strictness of the language and standard toolset helps, but it's far from a guarantee that enterprise Rust will be readable and clear.
I think the built-in array type is illustrative. In both languages (C++ and Rust) the initial 1.0 language offers a built in array type that is provided with built-in syntax and parsing but isn't as good as the user-made container types, so on day one the situation is OK, yeah, we do have arrays but you should likely avoid them.
In C++ that just remains the case, C++ 20 has poor built-in arrays and a note saying we built another array type that you should actually use, it's in our standard library.
Meanwhile in Rust they've been improving their built-in arrays, using const generics, implementing IntoIterator for arrays, and so on. Rust 2021 in a compiler today has pretty nice built-in arrays that behave how you'd expect for a container, a sophisticated programmer might notice that Default isn't implemented for your array of 64 integers, but such sharp corners are now few and far between and further refinements continue.
The resulting conversation is more open to change, even though Editions can't actually do magic they can conceal some pretty deep compiler magic like the hack to enable IntoIterator for arrays yet keep working Rust 2015 and Rust 2018 code that assumed into_iter() on an array will go via a reference. Being able to get to 90% of what people wanted with no magic meant the conversation about extra magic happened and it might otherwise not have.
Editions also spur language innovations that make further edition work easier. Rust 1.0 did not have any way to talk about an identifier if it collided with a keyword, which of course means if you reserve a new keyword now you can't access identifiers which used the now-reserved name. Rust 2018 introduces raw identifiers to fix that, if you really insist on naming your function "try" you can write r#try despite the existence of the keyword try.
I think these benefits are cumulative, and although Rust 2045 might have some cruft it will have a lot less than C++ 23 let alone C++ 44.
Mainly, because:
1 - They require the whole code, including all third party dependencies to be available to the compiler;
2 - There is the issue about possible inconsistencies across Rust compilers, when they start to be more widespread;
3 - They are relatively constrained the scope, e.g. semantic differences across versions and how that can be handled across crates public API
Let's see how editions take care about the many items that are yet to stabilise.
Naturally Rust being 30 years younger (approximately), it will always get less cruft.
Maybe by 2045 it can manage to do the same play C++ did on C, and there will be a LLVM replacement in Rust, while at the same time, there will be domains that regardless how much cruft C++ has gained, they will continue to use, just like it almost impossible to take C out of UNIX clones and embedded, no matter how much C++ has tried.
If Rust doesn't want the enterprise and game development markets it is ok, there is enough space for all.
As to Game Development, well, one of the things Rust has been trying to do is avoid toxic people and if you wanted a concentrated supply of toxic people the video game industry is where you'd look. I expect there will be a lot of Rust in or near video games in the next decade, but I already pity the people working on them.
Hyrum's law will indeed bite multiple Rust implementations, as it already bites Rust on non-x86 CPUs because a low level language cannot entirely conceal implementation details. This is already a huge leap over C++ where you get to tickle previously undetected Undefined Behaviour if you change compilers because (safe) Rust stays safe even if you're astonished that e.g. documentation saying "the order is not defined" really means "the order is not defined" despite the fact you tested it on your laptop last week and that's how it worked. Your bad program might have bugs but it doesn't suddenly exhibit nonsense behaviour.
Fundamentally Rust's Editions are about the fact that we don't get it right first time every time. In C++ having settled on the claim that (quoting Stroustrup) "this array concept is inherently low level" the built-in array is basically abandoned as unusable garbage forever because to do otherwise would admit a mistake. In contrast Rust says sure, arrays don't yet have all the features you expect of first class containers, we will improve the language to deliver that.
I think this is a healthier philosophy and it's already successful. It isn't a panacea, but it is a very noticeable improvement.
As to taking care of items that are yet to stabilise, what's to see here? Even for something like generators that is far from finished, the keyword is reserved already, you probably wouldn't wait for an edition to land it, once it was stable you just flip the toggle and it works.
I used to be the opposite in the ancient times. Would read a book and then start programming. But then the books were relatively tiny. Now most languages has matured to the state of having an insane amount of features. And the result is definitely what you say. Just read some brief overview on basic language constructs and then proceed by learning on on-need basis as you progress.
Among the others I program in C++ for example but I would shoot myself if asked to read something resembling its complete description. Sorry I have a life to live. And I am using only subset of C++ that solves my particular needs. If I feel my code does not look nice when doing some particular stuff then the time comes to do some more reading.