It should come as no surprise that life lately has been dominated by the upcoming Rust 1.0 release. But now that the beta release is out the door, I’ve started to give some thought to what we ought to do next. Obviously, there is no shortage of good ideas out there for how to grow the language. Just as obviously, we need to be careful about what we implement and when we implement it.
This post represents an initial stab at assigning priorities to the upcoming tasks. It is based on my attempts to survey the many proposals for extending Rust, as well as talking things over with users of Rust (particularly production users). I’d really love to hear more feedback (here on the discuss thread, ideally). I also expect we’ll be constantly adjusting priorities as we go. I plan to draw up a public Google doc that we keep up to date tracking this sort of high-level priorities information; haven’t done it yet.
How to decide what to prioritize
So how should we decide what to work on now versus later? I think the two most important criteria are time-sensitivity and impact:
- Time-sensitivity. Some changes are just going to get harder and harder to do over time. Particularly around unsafe code, de facto dependencies and assumptions can crop up and make it hard to introduce changes. Some examples where this might be relevant are dynamic drop, allocators, and tracing support.
- Impact. Some features have the potential to affect a large number of problems, or else a large number of users. An example of the former is trait specialization, which can potentially address a number of existing problems and needs. An example of the latter is improved compilation performance, which affects every Rust user.
These things seem like they are the most urgent to me. Many of them already have people working on them. Those that don’t will be top priority as people-power becomes available. I’ve put down names of owner(s) for each item: these are the people that are currently planning on driving the design and impl work forward. If you’d like to be more involved in one of these items, they would be good people to contact!
Library APIs. We’ve stabilized a large portion of std, but there are many important things that didn’t make it. Issue 24028 has a more complete list, but I want to highlight a few things in particular as needing attention:
- Filesystem APIs. We plan to flesh these out so that we can get the cargo implementation running on stable Rust.
- Memory allocation APIs. We know that being able to allocate a bag-of-bytes would be very useful for a number of projects. The main reason we haven’t pursued this is because of concern about possible interactions with GC/tracing support (see below). But we plan to introduce some kind of stable allocator API very soon.
In addition, we would like to put some energy into developing useful libraries that are not (necessarily) part of the standard library but which fill important gaps. For example, I know @aturon is chomping at the bit to build some parallel programming abstractions. Owner: aturon, acrichto.
Better Windows and ARM support. Both Windows and ARM are huge, important markets where Rust support still needs work. Improving our support in these areas will help make Rust attractive for a larger number of people. With respect to Windows, the overall goal is to remove our dependence on the MinGW toolchain but this will take a number of steps to achieve (more discussion here is needed). With respect to ARM, the primary goal is support for the ARM64 architecture. Owner: brson.
Faster compilation. We’ve put a lot of effort into building up the feature set and relatively little into optimizing. There’s a lot of low-hanging fruit here, but also an opportunity to rearchitect parts of the compiler and gain huge wins. I’d like to see progress towards parallel and incremental compilation, for example, both in the backend (LLVM side) and the front end (type checker, etc). I’d also really like to take some time to overhaul the trait matching and type inference scheme; it needs some work to better handle associated types in particular. Owner: nrc, nmatsakis.
Better support for distributing Rust libraries and programs. There
are a number of things we can do to make distributing Rust executables
and libraries easier.
cargo install is an oft-requested feature
that will require some careful design. Another piece here is being
able to distribute binaries with minimal external dependencies; being
able to link to MUSL might be a big help
here. Owner: acrichto.
Better tool support. While Rust now has fairly decent debuginfo, it can always be better. And it’d be great to have integration with other tools like fuzzers, line coverage, profilers, etc. Having a healthy ecosystem with quality tools – and in particular, being able to leverage C tools where it makes sense – seems crucial to widespread adoption. Owner: nrc, brson.
Dynamic drop. We need to remove the zeroing flags and implement the dynamic drop semantics we agreed to in RFC 320. It’s important to do this sooner rather than later to avoid de facto dependencies arising from unsafe code (Felix made a mitigating change aimed at encouraging people to write forwards compatible code, but that was only a stopgap measure). Furthermore, this change should improve compilation and execute performance across the board. Owner: pnkfelix.
Allocators/Tracing. We need to offer more control over memory allocation. This touches on a number of areas. For example, it can be useful to use different kinds of allocators in different parts of your program (in the direction of RFC 244). It would also be good to make it easier to control the global allocator. We need a stable routine like malloc/free. And, crucially, we’d like all of that while also having the ability to trace live values on the stack, so that we can integrate with garbage collectors – this is particularly important when linking to dynamic langauges or other GC’d runtimes, but might also be useful in plain Rust, particularly for some kinds of non-blocking data structures. (LLVM’s new and improved support for tracing offers exciting opportunities here.) This is a very time-sensitive topic: if we don’t act soon, the growth of unsafe libraries may severely limit our options here. Owner: pnkfelix.
Specialization. Specialization allows there to be multiple implementations of a given trait for a given set of types. Over the past few months or so, I’ve seen numerous examples of situations where specialization could help to address coherence limitations or to improve performance. I think it’s important to get the ball rolling on a design here. Owner: aturon, nmatsakis.
Virtual structs. For certain use cases, there is an urgent need to generalize the current setup of enum/structs and traits. This led to the so-called “virtual struct” proposal in the past. In the past, we focused on the efficiency questions, but I think there is also a need to make some patterns more convenient to write. In any case, previous experience suggests it’s going to be tricky to get the design right here, so I expect we’ll wind up spending some amount of time iterating in the RFC process. I’ve been doing a lot of thinking on this lately and I hope to put out some blog posts soon working through some aspects of the problem and the design space. Owner: aturon, nrc, nmatsakis.
Possibly high priority
There are some tasks whose priority feels harder to calculate. They are both tasks that will take a fair amount of effort, but it might be worth it!
Borrow checker improvements. I would very much like to start working on a concerete design to solve #6268 and #6393. Prioritizing this feels a bit hard though. On the one hand, both of these problems are (usually) relatively easy to work-around, but they affect a large number of new users, and removing them might go a long way towards improving the initial “Rust experience”. Owner: nmatsakis.
Improved macros and syntax extensions. Rust 1.0 includes the
macro_rules system, but it has a lot of known
problems. Perhaps the biggest is the lack of “privacy” or "unsafety"
hygiene (meaning that it’s not possible to define macros that have
privileged access over normal code). This prevents macros from being
used to define abstraction barriers. There is also no integration with
the normal import/export mechanisms of the language. Going further,
Rust has always intended to have the ability to link in “syntax
extensions”, which are macros whose implementation is written in Rust
rather than using a declarative form. There is a prototype now but the
API exposes far too many of the compiler internals to be considered
stable. We need to better identify the use-cases we’d like to support
and what kind of stable API we can offer. This is also somewhat tricky
to characterize: any changes here will be backwards compatible, and
many of the same effects can be achieved with pre-processing for the
time being. On the other hand, several popular libraries (e.g., serde,
sql, regex) have demonstrated the power and appeal of syntax
extensions. Owner: nrc.
There are a grab-bag of smaller RFCs and changes I’d like to see forward motion on. These issues seem to be relatively self-contained: it will still take some time to find a design everyone is happy with, but it doesn’t look like the design here will have large interactions with the rest of the language.
?operator for improved error-handling. See rust-lang/rfcs#243.
+=operators. See rust-lang/rfcs#953.
- Overflow ergonomics. It’d be nice to be able to write overflowing operations more concisely, when you want them. Probably. See this internals thread.
Rvalue promotion. The idea here is to allow constants like
&[1, 2, 3]to have static lifetime. Currently, they are limited to a lifetime that would permit them to be stored on the stack. A lot of the work on identifying which cases are legal has been done, but it needs to be written up and thought through a bit more. See rust-lang/rfcs#1056.
Smart pointer enhancements. In particular, we need support for
NonZero. Unlike the other cases, the design here actually is subtle, but we should be able to base the work on the existing traits in a fairly straightforward way. See rust-lang/rfcs#997.
This final group includes changes that I see as being somewhat longer term. These are mostly larger, cross-cutting changes that will deeply affect the language and libraries. I think it’s great to keep thinking and working on these larger items – particularly on their design – but they are less likely to be integrated into Rust proper until other large features have been completed. This is both because it takes a lot of work to finalize the design and because the design will benefit from more time and experience. It seems likely that with an influx of new users, we will find new use cases (or new ways to solve the problem without changing the language).
Passing DST by value: It’d be great to be able to pass DST
objects by value. At minimum, we need to be able to make
Box<FnOnce()>work, but there are other interesting use cases too. See rust-lang/rfcs#990.
- impl Trait: This case is tricky to prioritize. On the one hand, there is an urgent need to have some way to return closures and iterators without boxing them, which argues for doing it soon. However, this interacts with many parts of the type system, and there could be a lot of subtlety to handle, which argues for holding off until we have time for dust to settle. See rust-lang/rfcs#105.
Generic integer parameters: Sometimes it’d be nice to be able to
write an impl parameterized over an integer constant, like
impl<T,N> Trait for [T;N]. This might also be done through improved support for associated constants:
impl<T,N:IsizeConst> Trait for [T; N::Value]. The primary challenge here in terms of the design is to decide how far we will go in trying to evaluate whether two constants are equivalent when we can’t compute a precise value; as far as the implementation, it’d probably be nice to do some refactorings of the associated type implementation first. See rust-lang/rfcs#884.
- Finalizing the closure traits: Right now you can’t manually implement the closure traits. The reasoning is explained here, bu the key idea is to remove the “rust-call” ABI hack and replace it with…something. This might be variadic generics, or it might just be integrating the ‘untupling’ into the normal Rust ABI. It’s not entirely clear. This also interacts with passing DST by value, described above.
Smoother C and C++ integration: How cool would it be to be able
#includeheader files, or call methods on (simple) C++ objects (and have Rust code be called in return). This could be really useful for integrating Rust into existing projects.
async/await/yield: I’d like to see some sort of transform here,
and I think integrating it into the compiler and type-system is
worthwhile since we can be more accepting. But it bears some
thought, we may be able to extend the type system in a generic way
and then make
yielda pure front-end transform See rust-lang/rfcs#388.
HKT: Lots of generic programming traits (e.g.
Iterable) seem like they might benefit from higher-kinded types. But higher-kinded types also bring a lot of complexity, and there might be other ways to solve the problem (e.g. the existing higher-ranked trait bounds that we have). See rust-lang/rfcs#324.
- Negative bounds: This is related to specialization, but different. I am concerned about the use of negative reasoning due to forwards compatibility concerns, though we have a precedent now for how to handle it. Still, I have a feeling that the need for negative bounds will be greatly diminished if we pursue specialization See rust-lang/rfcs#1053.
- Extended reference types like &own or &uninit: There are various use cases that the existing reference types don’t quite cover. One way to address those is extending the language, though I’m personally very reluctant to do this without great justification. I’d rather wait and see how far we can get with library-based approaches See rust-lang/rfcs#998. This interacts with passing DST by value as well.