Over the past years, Rust has grown from a language used by a few dedicated users into a well-known language used by lots of highly visible projects and successful companies. As the Rust user base, the community, and the ecosystem continues to grow, we need to look forward and consider how we need to scale to adapt to the needs of the ever expanding Rust ecosystem.
Recently, the compiler team shared their blog post detailing their ambitions for 2022, and the language team published a roadmap with their vision for Rust in 2024.
In this blog post, we, the Rust library team, will share our perspective on the future of the Rust standard library and the library ecosystem.
It's important to note that the role of the team is to coordinate changes and to guide, review and decide. The majority of the work itself is done by contributors, like yourself, both in and outside the Rust team. While we often also participate in design and implementation work, we do so as contributors, like everyone else.
What follows is an (incomplete) summary of topics we think are important and would like to coordinate and guide; things that we'd love to see happen, as an invitation and source of inspiration.
Scalability
As mentioned above, the Rust language, standard library, and ecosystem is growing and getting more mature. We need to invest in ways to keep evolving these smoothly.
Evolvability of the standard library and fixing mistakes
The stability guarantee of Rust makes it hard to evolve the standard library. Unlike most crates, we cannot release a new major version, as that would effectively be releasing a 'Rust 2.0'. So, once an API is stable, we have to keep it there forever, meaning that we have to be extremely careful when stabilizing anything new.
While we are very careful with adding new APIs, mistakes can still happen. There are a few things we would do differently if we could go back in time, based on current experience. There are not a lot of these cases, but over time these can still accumulate to the point that it'd be useful to have a mechanism to correct past mistakes.
The Rust language has the concept of editions
to be able to make breaking changes in the language itself, without disrupting Rust users.
The library, however, can make very limited use of editions to correct mistakes.
We have used them for the panic!()
macro
and the prelude.
However, in general, it's extremely tricky to make use of the edition mechanism for backwards incompatible
library changes, as crates of different editions can be mixed, while all using the same standard library.
There are also cases when adding a new API can subtly break existing Rust code,
even when not changing any existing API.
This can happen, for example, when a type gets a new method that was already available through
a popular trait, such as itertools::Itertools
or num::Integer
.
Adding a method to the standard library can result in an existing method call resolving differently,
potentially breaking code.
This is usually considered 'acceptable' breakage, but as Rust usage grows,
the impact of such breakage increases, often making such breakage unacceptable in practice.
So, in order to keep evolving the standard library, we'd like to collaborate on language features that alleviate these issues:
- Edition based method disambiguation
- A way to fix the
Range
types, such that1..2
can beCopy
. - A way to remove or improve lock poisoning without breaking existing code.
- General mechanisms to provide for the library what editions provide for the language.
People and collaboration
The most important thing to keep Rust and the ecosystem scalable, are the people: Rust team members, maintainers of crates in the ecosystem, reviewers, contributors, and so on. It's important we keep working on how we collaborate and make it as easy as possible for everyone to get involved in a way that works for them.
Concretely, we want to work on:
- Better and more complete guidelines for contributors and reviewers; and
- More interaction with the rest of the ecosystem.
Making std
less special / Empowering other crates in the ecosystem
The standard library uses a
huge amount of unstable language features
that other crates in the ecosystem cannot (or should not) use.
While this is unavoidable for core
, because it contains everything related
to Rust's built-in types, we should be able to make alloc
and std
less
dependent on unstable features.
Maybe some day these libraries could be no different than any other
popular crate in the ecosystem.
A big part of the work here will be in collaboration with the language team, to help move the unstable language features we need towards a state where they can be stabilized.
Adapting to different platforms
As Rust's popularity increases, it is used on an increasingly wider variety of platforms.
The Rust standard library does an okay job at abstracting away some of the
differences between popular platforms like Linux and Windows,
through things like File
and TcpStream
,
but we don't do a great job for targets that do not look like those,
such as Wasm or kernel modules.
For example, core
includes f32
and f64
, even if the platform doesn't support floating point operations,
and std
includes File::open
, even if it isn't implemented and always fails on the specific platform you're targeting.
In order to better support the ever growing diversity of platforms Rust is used on, we would like to collaborate with the language and compiler teams to make it easier for the standard library to properly support targets with very different needs, without it becoming hugely inconvenient for maintainers, contributors, or users:
- Make it easier to port std to a new platform, possibly allowing the relevant code
to live outside of the
rust-lang/rust
repository for less popular platforms. - A better way to allow only parts of
std
to be available, depending on the platform. For example, awhere Platform: Unix
bound, or something like a#[cfg]
portability lint. - A way to allow non-portable functionality to be available when on platforms
that would support it, such as allowing infallible conversion between
u64
andusize
in code that declares it only runs on 64-bit platforms. - Make the standard library more modular, allowing to disable e.g. floating point support or file system support on certain platforms.
Improving and adding new APIs
A main focus of the library team is and will always be the public interface of the standard library. As of last year, we even have a separate team to make the final calls for API changes and additions: the library API team.
Rust purposely has a minimal standard library. Lots of commonly used functionality is found in other crates in the ecosystem, rather than the standard library.
Where exactly we draw the line between things that should and shouldn't go in the standard library can be tricky to define and is somewhat flexible, but there are a few categories we're most interested in.
Ergonomics
A lot of additions to the standard library are very small ones that increase ergonomics. Quite often, these are things that were already possible in some way, just not in an ergonomic way. Some recent examples are:
abs_diff()
Path::is_symlink
iter::from_fn
NonZero*::saturating_add
While we always have to consider the trade-off for niche features to the already large interface on some types and traits, additions like these continue to happen regularly.
Standardizing some bigger features the ecosystem needs
As Rust grows into new territories, there is more and more a need for certain features to be included in the standard library. This is especially true for things where a consistent, standard, interface is important. Some of the bigger examples are:
- Async traits and functions
- Allocators and fallible allocation
- Error and panic handling
- Portable SIMD
- Benchmarking and custom test/bench frameworks
Reducing and improving unsafe code
By providing the right low level APIs and abstractions, we can greatly minimize
the amount of complex unsafe code that users need to write. Tools like
MaybeUninit
guide users to correct unsafe code that's easy to follow and
prove correct. Even better, some APIs can entirely remove the need for unsafe
code in many situations.
This includes situations where users tend to reach for unsafe
for performance reasons.
std::arch
std::simd
- Scoped threads
- More atomic primitives
- '
Iterator
' with static length for arrays - Improving
MaybeUninit
and related methods - Extending
NonNull
and pointer methods - A more complete interface to
OsString
,Path
, andCString
- Documentation for
Pin
and other 'unsafe' types - File descriptors (
OwnedFd
,AsFd
, etc) and handles (OwnedHandle
,AsHandle
, etc)
Improving implementations of things within the standard library
Historically, the implementation details of the standard library got less attention than its public API. Recently, however, we're seeing more and more contributions towards improving the implementation of various parts of the standard library.
These are some parts that we're especially interested in seeing improvements in:
core::fmt
and the implementation offormat_args!()
andfmt::Arguments
- Synchronization primitives like
Mutex
,RwLock
, andCondvar
- Cleanups in platform-specific code in
std::sys
- Avoiding allocations wherever possible, such as when calling functions in
std::fs
- Making widely used types such as
std::io::Error
more light-weight - Cleaning up all unnecessary
SeqCst
memory ordering - Optimizing thread local variables
Conclusion
We hope this summary provides a healthy amount of inspiration and excitement, and gives you an idea of what direction the library team is headed. If you want to help out, whether you want to work on implementation work, design, documentation, organisation, or any other kind of helpful work, you're warmly invited to get involved!