Async closure thoughts from Michael Goulet (compiler-errors) and thanks for his contributions!

post:

and zulipchat discussion link .

This post attempts to motivate some of the concrete technical reasons why the #![feature(async_closure)] that I (Michael Goulet) 've been working on recently[1][2][3][4] is so complicated. Specifically, why can't we just use || async {} that we can express on stable today, an interesting but very important note about the relationship between a "lending" FnMut and the FnOnce trait that I haven't seen written anywhere yet, and how async closures are a tractable solution to an otherwise intractable problem with lending closures.

  1. https://github.com/rust-lang/rust/pull/120361 :leftwards_arrow_with_hook:

  2. https://github.com/rust-lang/rust/pull/120712 :leftwards_arrow_with_hook:

  3. https://github.com/rust-lang/rust/pull/123518 :leftwards_arrow_with_hook:

  4. https://github.com/rust-lang/rust/pull/125259 :leftwards_arrow_with_hook:

tl;dr

  • Async closures need to be lending, since they return futures that may borrow from the closure's captures.
  • So they need to implement some LendingFnMut trait.
  • However, LendingFnMut is not easy to introduce into the current Fn->FnMut->FnOnce trait hierarchy, because LendingFnMut cannot be a subtrait of FnOnce. Why? Because:
    • The value returned by a LendingFnMut implementation typically differs from that returned by FnOnce, but they're inherited by the current subtraits.
    • So let's split out these two types – however, in general, there's no meaningful value for a lending closure to return when called in a way that consumes the closure.
    • That is: lending closures typically do not implement FnOnce at all.
    • So we can't just fix FnMut and make it "just work".
  • However, Async closures do have an obvious FnOnce implementation that can be derived programmatically from their LendingFnMut implementation.
  • To simplify closure signature inference, it's easiest to stop using the most general definition (LendingFnMut) and specialize this trait for async – we introduce AsyncFn/AsyncFnMut/AsyncFnOnce.
  • But to keep space for future generalization, we can hide this behind an async trait bound modifier.
7 Likes

BTW Async Closures RFC (#3668) just came out

2 Likes

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.