Bring the Async Rust experience closer to parity with sync Rust

Metadata
Point of contactTyler Mandry
Teamslang, libs, libs-api, types
StatusProposed for flagship

Summary

Over the next six months, we will continue bringing Async Rust up to par with "sync Rust" by doing the following:

  • Telling a complete story for the use of async fn in traits, unblocking wide ecosystem adoption,
  • Improving the ergonomics of Pin, which is frequently used in low-level async code, and
  • Preparing to support asynchronous (and synchronous) generators in the language.

Motivation

This goal represents the next step on a multi-year program aiming to raise the experience of authoring "async Rust" to the same level of quality as "sync Rust". Async Rust is a crucial growth area, with 52% of the respondents in the 2023 Rust survey indicating that they use Rust to build server-side or backend applications.

The status quo

Async Rust is the most common Rust application area according to our 2023 Rust survey. Rust is a great fit for networked systems, especially in the extremes:

  • Rust scales up. Async Rust reduces cost for large dataplanes because a single server can serve high load without significantly increasing tail latency.
  • Rust scales down. Async Rust can be run without requiring a garbage collector or even an operating system, making it a great fit for embedded systems.
  • Rust is reliable. Networked services run 24/7, so Rust's "if it compiles, it works" mantra means fewer unexpected failures and, in turn, fewer pages in the middle of the night.

Despite async Rust's popularity, using async I/O makes Rust significantly harder to use. As one Rust user memorably put it, "Async Rust is Rust on hard mode." Several years back the async working group collected a number of "status quo" stories as part of authoring an async vision doc. These stories reveal a number of characteristic challenges:

The next 6 months

Tell a complete story for async fn in traits

  • Unblock AFIT in public traits by stabilizing RTN and implementable trait aliases (unblock tower 1.0)
  • Ship 1.0 of the dynosaur crate, enabling dynamic dispatch with AFIT
  • Stretch goal: Implement experimental support for async fn in dyn Trait in nightly

Improve ergonomics around Pin

  • Ratify and implement an RFC for auto-reborrowing of pinned references
  • Stretch goal: Discuss and implement a design for safe pin projection

Work toward asynchronous generators

  • Have design meetings and ratify an RFC for synchronous generators
  • Have a design meeting for asynchronous iteration
  • Stretch goal: Ratify an RFC for unsafe binders

In H2 we hope to tackle the following:

  • RTN in type position
  • Ratified RFC for asynchronous iteration

The "shiny future" we are working towards

Writing async code in Rust should feel just as expressive, reliable, and productive as writing sync code in Rust. Our eventual goal is to provide Rust users building on async with

  • the same core language capabilities as sync Rust (async traits with dyn dispatch, async closures, async drop, etc);
  • reliable and standardized abstractions for async control flow (streams of data, error recovery, concurrent execution), free of accidental complexity;
  • an easy "getting started" experience that builds on a rich ecosystem;
  • good performance by default, peak performance with tuning;
  • the ability to easily adopt custom runtimes when needed for particular environments, language interop, or specific business needs.

Design axioms

  • Uphold sync Rust's bar for reliability. Sync Rust famously delivers on the general feeling of "if it compiles, it works" -- async Rust should do the same.
  • Lay the foundations for a thriving ecosystem. The role of the Rust org is to develop the rudiments that support an interoperable and thriving async crates.io ecosystem.
  • When in doubt, zero-cost is our compass. Many of Rust's biggest users are choosing it because they know it can deliver the same performance (or better) than C. If we adopt abstractions that add overhead, we are compromising that core strength. As we build out our designs, we ensure that they don't introduce an "abstraction tax" for using them.
  • From embedded to GUI to the cloud. Async Rust covers a wide variety of use cases and we aim to make designs that can span those differing constraints with ease.
  • Consistent, incremental progress. People are building async Rust systems today -- we need to ship incremental improvements while also steering towards the overall outcome we want.

Ownership and team asks

This section defines the specific work items that are planned and who is expected to do them. It should also include what will be needed from Rust teams. The overall owner of the effort is Tyler Mandry. We have identified owners for subitems below; these may change over time.

Overall program management

TaskOwner(s) or team(s)Notes
AFIT story blog postTyler Mandry

Return type notation

TaskOwner(s) or team(s)Notes
Initial implementationMichael GouletComplete
Author RFCNiko MatsakisComplete
RFC decisionTeam langComplete
Finished implementationMichael Goulet
Standard reviewsTeam types compiler
Stabilization decisionTeam lang

Unsafe binders

TaskOwner(s) or team(s)Notes
Initial implementationMichael GouletStretch goal
Author RFCNiko MatsakisStretch goal
RFC decisionTeam langStretch goal

Implementable trait aliases

TaskOwner(s) or team(s)Notes
Author RFCTyler Mandry
ImplementationMichael Goulet
Standard reviewsTeam types compiler
RFC decisionTeam lang types

async fn in dyn Trait

TaskOwner(s) or team(s)Notes
Lang-team experimentNiko Matsakis(Approved)
ImplementationMichael GouletStretch goal

Pin reborrowing

TaskOwner(s) or team(s)Notes
ImplementationEric Holk
Author RFCEric Holk
RFC decisionTeam lang

Safe pin projection

TaskOwner(s) or team(s)Notes
Lang-team experimentTeam lang
ImplementationStretch goal
Design meetingTeam langStretch goal

Trait for generators (sync)

TaskOwner(s) or team(s)Notes
ImplementationEric Holk
Author RFC
RFC decisionTeam libs-api lang
Design meetingTeam lang2 meetings expected

Trait for async iteration

TaskOwner(s) or team(s)Notes
Design meetingTeam lang libs-api

Dynosaur 1.0

TaskOwner(s) or team(s)Notes
ImplementationSantiago Pastorino
Standard reviewsTyler Mandry

Definitions

Definitions for terms used above:

  • Discussion and moral support is the lowest level offering, basically committing the team to nothing but good vibes and general support for this endeavor.
  • Author RFC and Implementation means actually writing the code, document, whatever.
  • Design meeting means holding a synchronous meeting to review a proposal and provide feedback (no decision expected).
  • RFC decisions means reviewing an RFC and deciding whether to accept.
  • Org decisions means reaching a decision on an organizational or policy matter.
  • Secondary review of an RFC means that the team is "tangentially" involved in the RFC and should be expected to briefly review.
  • Stabilizations means reviewing a stabilization and report and deciding whether to stabilize.
  • Standard reviews refers to reviews for PRs against the repository; these PRs are not expected to be unduly large or complicated.
  • Prioritized nominations refers to prioritized lang-team response to nominated issues, with the expectation that there will be some response from the next weekly triage meeting.
  • Dedicated review means identifying an individual (or group of individuals) who will review the changes, as they're expected to require significant context.
  • Other kinds of decisions:
    • Lang team experiments are used to add nightly features that do not yet have an RFC. They are limited to trusted contributors and are used to resolve design details such that an RFC can be written.
    • Compiler Major Change Proposal (MCP) is used to propose a 'larger than average' change and get feedback from the compiler team.
    • Library API Change Proposal (ACP) describes a change to the standard library.

Frequently asked questions

Why work on synchronous generators if your goal is to support async?

There are three features we want that all interact quite heavily with each other:

  • Sync generators
  • Async generators
  • Async iteration trait

Of the three, we think we are the closest to ratifying an RFC for synchronous generators. This should help clarify one of the major outstanding questions for the other two items; namely, the relation to pinning. With that out of the way, we should better be able to focus on the iteration trait and how well it works with async generators.

Focusing on pinning first also synergizes well with the efforts to improve the ergonomics of pinning.