Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Simplify language, add links, formatting fixes #2443

Merged
merged 1 commit into from
Oct 18, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 26 additions & 20 deletions src/concurrency/async-pitfalls/async-traits.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,22 +4,20 @@ minutes: 5

# Async Traits

Async methods in traits are were stabilized only recently, in the 1.75 release.
This required support for using return-position `impl Trait` (RPIT) in traits,
as the desugaring for `async fn` includes `-> impl Future<Output = ...>`.
Async methods in traits are were stabilized in the 1.75 release. This required
support for using return-position `impl Trait` in traits, as the desugaring for
`async fn` includes `-> impl Future<Output = ...>`.

However, even with the native support today there are some pitfalls around
`async fn` and RPIT in traits:
However, even with the native support, there are some pitfalls around
`async fn`:

- Return-position impl Trait captures all in-scope lifetimes (so some patterns
of borrowing cannot be expressed)
- Return-position `impl Trait` captures all in-scope lifetimes (so some patterns
of borrowing cannot be expressed).

- Traits whose methods use return-position `impl trait` or `async` are not `dyn`
compatible.
- Async traits cannot be used with [trait objects] (`dyn Trait` support).

If we do need `dyn` support, the crate
[async_trait](https://docs.rs/async-trait/latest/async_trait/) provides a
workaround through a macro, with some caveats:
The [async_trait] crate provides a workaround for `dyn` support through a macro,
with some caveats:

```rust,editable,compile_fail
use async_trait::async_trait;
Expand Down Expand Up @@ -47,11 +45,11 @@ async fn run_all_sleepers_multiple_times(
n_times: usize,
) {
for _ in 0..n_times {
println!("running all sleepers..");
println!("Running all sleepers...");
for sleeper in &sleepers {
let start = Instant::now();
sleeper.sleep().await;
println!("slept for {}ms", start.elapsed().as_millis());
println!("Slept for {} ms", start.elapsed().as_millis());
}
}
}
Expand All @@ -71,13 +69,21 @@ async fn main() {
- `async_trait` is easy to use, but note that it's using heap allocations to
achieve this. This heap allocation has performance overhead.

- The challenges in language support for `async trait` are deep Rust and
probably not worth describing in-depth. Niko Matsakis did a good job of
explaining them in
[this post](https://smallcultfollowing.com/babysteps/blog/2019/10/26/async-fn-in-traits-are-hard/)
if you are interested in digging deeper.
- The challenges in language support for `async trait` are too deep to describe
in-depth in this class. See [this blog post] by Niko Matsakis if you are
interested in digging deeper. See also these keywords:

- [RPIT]: short for
[return-position `impl Trait`](../../generics/impl-trait.md).
- [RPITIT]: short for return-position `impl Trait` in trait (RPIT in trait).

- Try creating a new sleeper struct that will sleep for a random amount of time
and adding it to the Vec.
and adding it to the `Vec`.

</details>

[async_trait]: https://docs.rs/async-trait/
[trait objects]: ../../smart-pointers/trait-objects.md
[this blog post]: https://smallcultfollowing.com/babysteps/blog/2019/10/26/async-fn-in-traits-are-hard/
[RPIT]: https://doc.rust-lang.org/reference/types/impl-trait.html#abstract-return-types
[RPITIT]: https://blog.rust-lang.org/2023/12/21/async-fn-rpit-in-traits.html