I've started learning Rust in 2018 first reading a bit about it, then started practising. What seduced me in the first place as a person with long C++ experience is Cargo - Rust's package and build manager. I knew package managers from Python and Ruby, and I know CMake which I'm not a big fan of, but Cargo pulverises them thanks to simplicity and easiness of use for the first time. The power of the modern languages lies in their ecosystems and C++ still sucks in this aspect. More about this later.
Syntax & Code Style
At first sight syntax of Rust may look like C and in case of more advanced code like C++. But, while elements like closing and opening brackets are, most other aspects differ. Function definitions use the simple keyword
fn while variable declarations use the keyword
let. In C both elements are and in C++ both elements can be keyword-less, as the return type start the function declaration or definition and variable type starts its declaration. Variables differ even more in the global context. Functions' return types in Rust look like in C++'s functions declared with
auto keyword which may optionally be declared after
So, syntax-wise there are similarities, but not really close. Sometimes code looks closer to typed Python 3 than to C. Next, 2018 edition makes code rich with abstractions more idiomatic and preferred what makes use of closures quite common. They look to me like totally taken from Ruby, aren't even close to C++'s lambdas. Then modules and privacy rules make Rust completely different than C with its very old school header files and link-time dependencies. As long as you don't need to use an external non-Rust library you don't care about linking - dependencies are sorted by Cargo.
As I already mentioned, idiomatic Rust is rich in usage of closures. The nice part is such code is as effective and well-optimized as code written in a classic imperative way. Rust allows both, so you may see a lot of code using for loops and ifs from Rust beginners around, while programmers who dived deeper into Rust are going to use more functional aspects of the standard library and use more iterators, mapping and filtering. This is at the same time advantage and disadvantage of Rust - while allowing beginners to grasp the meanders of Rust easier, it opens door to mixed style in a single project what's not good from a software engineering standpoint. We can't have all.
One of Rust promises is memory safety. Yeah, Ada promised that as well. Why Rust wins over Ada then? The (in)famous borrow checker works at compile time preventing programmers from doing things that overtime would be perceived as stupidities leading to memory leaks or unmaintainable code. I've read authors of SPARK (a subset of Ada) are looking at Rust mechanisms in practice to reduce the strain of checks at runtime that Ada normally did.
A general rule of thumb in Rust is you can refer to a variable immutably multiple times, but only one mutable access is available at a time thanks to borrowing or a move. Things are getting a little bit more complicated in case of multithreading as some runtime cost is inevitable. But then that's not much different from traditional multithreading in C or C++, but with much fewer chances to screw things.
RAII as known from C++ works in Rust what enables constructions caring about own proper initialisation and destruction freeing the programmer from thinking how the correct flow would look like for every use. That's opposite to C. Many finger point this as Rust's disadvantage hiding the implementation and logic flow behind harder to follow abstraction, but that seems to be the view of people who prefer spending long hours on debugging their code instead of writing it right at first try. These are heavily colliding world views.
C++ programmers shall know move semantics since C++11. In C++, however, the move semantics is optional while in Rust it's the default. There are interesting implications of that state of matter. The correct ownership in C++ is a matter of code's hygiene and can be misused, Rust treats ownership very seriously and if something has been moved it's no longer available in the scope. This is a significant philosophical difference in Rust you can't screw a moved object, in C++ incorrectly written move constructor may lead to very nasty and very hard to nail down bugs if any reference to moved content remains in the source object. Rust doesn't require implementing explicit moves at all as that's the default, only if copies are needed extra implementations may be required (or derived).
In that sense, Rust's default move is a fulfilment of a software engineering dreams about immutability so often praised in functional languages. Here, we're getting a programming language which somehow brings both worlds together. That one element if ever brought to C++ would probably render Rust unviable for consideration, as many aspects of idiomatic C++ today already allow to write safe code (with a lot of warnings enabled and turned into errors), putting aside friendliness or Rust compiler's error messages.
Second, dependencies are managed in one place and each project controls them independently. There is no need to pull them prior to use as, for example, in
pip from Python ecosystem. Calling
cargo build will do all the job - that significantly simplifies starting with any code downloaded from GitHub or elsewhere. And it's a tremendous jumpstart for all beginners. Obviously, this is a perfect world for open source, but...
Third, the ecosystem is consistent. This is extremally contrasting with C++ world, where there is no common system of how source packages are formed and how they should be integrated into projects needing them. All attempts to find a solution so far roughly speaking failed in the long term. Standardisation committee started work on addressing this problem, but we're like at least 6 years from now till something workable will enter into play.
Every rose has its thorns. In case of Rust is the applicability into a serious commercial world. Proprietary libraries are rarely shared in the form of source code. Rust doesn't address such a potential need at the moment. Apart from other problems about commercialisation, this fact is something that cannot be neglected and properly working solution is a key to trust from commercial vendors of proprietary libraries. So far most businesses managed to operate within an open-source ecosystem or delivered libraries written in Rust and C linkables for their customers who still use traditional C or C++ toolchains.
The subject of Rust standardisations by official bodies recently returns in discussions more frequently. Many "old" languages are standardised, by ISO usually, these include C, C++ & Pascal. The last one is somehow out of fashion and flavours in practical use seem to vary from the standardized version. Then in case of C and C++ standardisation creates a common ground for all compiler manufacturers (in reality most of them share commercial EDG front end), but there is only one fully capable Rust compiler. No competition. No commercial implementation.
There is no money lying for any prospect compiler manufacturer at the moment. What creates a closed circle as standardization means cost. Who's going to fund the effort? At the moment the language expands rapidly, driven by RFC process and community efforts to implement new accepted features or depreciate those out of favour. There are editions which could be a good base for standard releases, but without commercial backing, nothing is going to happen.
Lack of standardisation makes the language and its great ecosystem much less interesting for large businesses needing standards and certificates, mostly safety certificates. The whole automotive and aeronautic industries are driven by standards, restrictions and certification of software and tools. That's unachievable for Rust at the moment. The only industries who can "afford" reaching for Rust programming language are those which hands remain untied by regulations. That usually means blockchain, cryptocurrency, some real-time trading and customer-oriented IoT, some of the farming industry where controlling software doesn't require certification.
For serious embedded systems all factors against Rust play in favour of C and eventually C++ (not that widely adopted yet). C is the most widely used programming language for embedded systems regardless of problems creating software and long term maintenance of it in C usually causes. There are no quantitative numbers available yet, but opinions of programmers who switched from C to Rust lead to believe savings on unexpected costs of maintenance and bug fixing could be huge. We need these numbers, but proper experiment would require multiple projects executed in both languages at the same time independently by skilled teams of programmers - rather unreal dream to fulfil.
Rust is great, but not for everyone. Yet.