My Take on Rust: The Unvarnished Truth
The Good
To be fair, Rust does have its strengths:
- Macros: Rust’s macros are reminiscent of Lisp’s, making them highly flexible and powerful.
- Type-Classes and Enums: The inclusion of traits and sum types, along with pattern matching, is a strong point.
- Standard Library: Handling strings as UTF-8 and other capabilities in its standard library are commendable.
- Mutability: Distinguishing mutability helps in understanding the moral purity of functions, enhancing code readability.
- Unsafe and Panic: While the use of unsafe can be concerning, it is akin to using an FFI. panic handling has its quirks, but it ensures explicit error handling.
Steep Learning Curve
Rust’s ownership model, while innovative, is complex. For many seasoned developers, wrapping their heads around borrowing, lifetimes, and ownership proves daunting. It’s not uncommon to hear frustrations over the borrow checker and the stringent rules that can halt progress, particularly for newcomers or those transitioning from more flexible languages like Python or JavaScript.
Development Speed
The strict compile-time checks that Rust employs ensure safer code but often at the cost of development speed. In many environments, developers need to iterate quickly, test ideas, and adapt on the fly. Rust’s stringent compilation process, while beneficial in the long run, can be seen as a hindrance to rapid prototyping.
Ecosystem Maturity
Rust’s ecosystem, though growing, is still not as mature as those of older languages like C++ or Java. This can mean fewer libraries and tools, which translates to more time spent writing boilerplate code or struggling to find maintained and reliable dependencies.
Community Exclusivity
While Rust’s community is vibrant and supportive, it sometimes carries an air of exclusivity. The steep learning curve and the dense technical jargon can create an unintentional barrier for newcomers, making the language seem like an elite club rather than a welcoming community for all.
Async Challenges
Rust’s decision to exclude a built-in runtime or scheduler means that alternative strategies had to be developed within the language. This has led to significant challenges, particularly with asynchronous code. The concept of “coloured functions” highlights the incompatibility between async and synchronous functions, leading to awkward and complex code when mixing the two.
Many developers prefer async libraries, but maintainers of well-established codebases can be resistant to adopt async, leading to further fragmentation. The lack of a unified async strategy results in a mess, especially when combined with iterators, making such code difficult to understand.
Magical Sugar Constructs
Rust’s use of magical sugar constructs, where the compiler automatically inserts dereferences, copies, and drops, can initially seem appealing. However, in practice, this often leads to confusing compile errors. The worst kind of error is when the compiler complains about something it generated rather than what you explicitly wrote. This is somewhat akin to Haskell’s use of monads; the more “magic” you introduce, the steeper the learning curve for newbies.
General Purpose Language
Rust is primarily marketed as a systems programming language, but it is increasingly used for web applications, command-line tools, and more. This broad adoption, while a testament to Rust’s capabilities, can be disappointing as it dilutes the language’s core purpose. Other languages like Go, Erlang, and Haskell may offer more productivity for general-purpose programming due to features like garbage collection and green threads.
Conclusion
Rust is not without merit—it offers unique advantages and a breath of fresh air in memory-safe programming. However, it’s critical to view it through a pragmatic lens and recognize that it may not always be the best tool for every job. Balance, as always, is key.