Boxable async fn

Impact

  • Able to easily cause some async functions, blocks, or closures to allocate their stack space lazilly when called (by 'boxing' it)
    • Combined with profiler or other tooling support, this can help to tune the size of futures
  • Boxed async blocks allows particular portions of a function to be boxed, e.g. cold paths

Milestones

MilestoneStateKey participants
Author evaluation doc💤
Feature complete implementation💤

Design notes

Example might be to use a decorator:

#![allow(unused)]
fn main() {
#[boxed]
async fn foo() { }
}

This does not have to desugar to -> Box<dyn Future<...>>; it can instead desugar to Box<impl Future>, or perhaps a nominal type to permit recursion.

Another approach is the box keyword:

#![allow(unused)]
fn main() {
box async fn foo() { }
}

We can apply the keyword modifier to async blocks and closures:

#![allow(unused)]
fn main() {
fn foo() -> BoxFuture<Output = ()> {
    box async { ... }
}
}
#![allow(unused)]
fn main() {
async fn stuff(s: impl AsyncIterator) {
    s.map(box async |x| { ... })
}
}

This is useful for breaking up future types to make them more shallow.