[Essay] Addressing concerns about Rust's stability

When we consider using Rust at work, it's important to have a response to the concerns that Rust lacks stability.

I believe that this perception has multiple causes:

  • the 6 week release cycle seems to be too fast for a stable language

  • a general misunderstanding of the notion of an edition

  • it's hard to know the significance of a major version versus a minor version vs an edition

  • an over-eagerness to adopt the nightly compiler

  • an over-eagerness to adopt unstable 3rd party dependencies

  • an unwillingness to release a 1.0 of your crate

Understanding Versions and Editions

One of the significant areas of confusion in Rust revolves around the concepts of versions and editions. In essence, Rust has three concurrent numbering systems.

The version signifies the ongoing progression of the language and its tools, following a semantic versioning scheme. Versions are broken into 'major versions' and 'minor version'. While it's true that a new compiler is released every 6 weeks, it's only the minor version that increments, and stability is retained.

The edition, on the other hand, is a way to introduce backward-incompatible changes without breaking existing code. Editions include changes that are compatible with previous editions and do not mean that older editions or their features become deprecated or obsolete. Rust compilers can accept code from all editions that existed when the the compiler was released.

Editions ensure that older code remains viable and functional, while Rust is able to remain nimble with new developments. This provides stability within the context of language that may evolve significantly from when the source code was originally written.

Understanding the significance of nightly

If you opt into nightly, then you're opting out of stability.

The nightly compiler contains the latest features and changes that are yet to be stabilized for the broader user base. While these features may be exciting and cutting-edge, opting into the nightly compiler too quickly can lead to a sense of instability, especially when the features are still in their testing and refinement phase. Therefore, it's recommended for most users—and essential for almost all commercial users—and projects to stick with the stable compiler unless there's a compelling reason to use nightly. Remember, 'nightly' is a playground for exploration, not a benchmark for stability.

Web frameworks are especially bad at promoting the stable compiler. The project creators want to use unstable APIs to enable an ergonomic experience for developers, but this means that some people will end up with burnt fingers. Unstable APIs do change. In fact, they're often removed. Many are unlikely to every be declared stable.

The Pre-1.0 Crates Dilemma

Deciding which dependency to bring into your project is a difficult process.

Rust's crate ecosystem suffers because there are many things that are almost-stable-but-not-quite. This happens because most projects are maintained by individuals on their own time. There's never quite enough time to finish the last 5% of the project. Very few major contributors to 3rd party libraries are paid to do so. Moreover, getting to a stable release means that you need to have a lot of confidence in your project. When you're only working on something sporadically, it's hard to be confident in it. Being an open source maintainer is a lot of work. Releasing a 1.0 is more work. Suddenly your users have expectations.

Another aspect contributing to the perceived churn is the reliance on pre-1.0 crates. It's crucial to remember that the version number of a crate reflects the stage of its development, with pre-1.0 crates still being in an experimental or unstable phase. Opting to use these crates in production can lead to a feeling of churn when changes occur. It's essential to be mindful of the stability guarantees provided by the crate versions and not hastily adopt crates that are not ready for production use.

The Reality

Rust is stable, but there are risks if you opt out of that stability. Just as the unsafe keyword allows you to take responsibility for upholding Rust's borrow checking rules, the nightly compiler also shifts the burden of responsibility.

The Rust project is dependable. Its commitment to semantic versioning (and the "no 2.0"), the edition concept, and the careful approach it takes to introducing new features, means that you can be assured that features declared as stable will remain so.

The Rust team meticulously tests all changes and ensures backward compatibility, allowing older code to run successfully even with new additions to the language. They have even created a comprehensive test system, Crater, that checks the impact of changes on all public crates to prevent breaking changes from slipping into stable releases. In some sense, the beta release channel exists purely to facilitate "crater runs".

It's safe to build with Rust

Change is inevitable in any software development process. However, Rust's strategic and thoughtful approach to managing change demonstrates a commitment to maintaining a stable ecosystem for developers. It's debatable whether this has been communicated clearly, but hopefully this post goes a small way to address that.