Creating a future of X from X?

Should it be possible to create a future from "itself"? Conceptually:

async fn foo(job: Job) {
   // ... blah ...
  let fut = foo(newjob);
  spawn(fut);
  // ... blah ...
}

I did a quick test and the compiler errored out about circular something something, so I assumed it's not supported, but thinking back my code may have been broken in other ways so now I'm not sure.

Not directly, but if you add jndirection you can. The simplest way is to use future.boxed().await, which basically reduces to (Box::pin(future) as Box<dyn Future + Send>).await

An alternative if you want to avoid the Box id to use pin_utils::pin_mut

pin_mut!(future);
(future as &mut dyn Future + Send).await;

The type erasure is key because of how Rust desugaes async functions. If the async function's type appears in any of it's fields (whatever the async function captures), it makes an infinitely large type. Note this is not a type whose size is infinite, the name of the type is infinite, and Rust can't represent that.

1 Like

Is this an intrinsic feature of async fn, or is it possible that a future desugaring could let this work?

There may be a desugarring that allows indirection without dynamic dispatch, but not without indirection. This is because all captures are stored inline, so if you tried this without indirection, you would get something like this:

struct AsyncFunc {
    recursive: MaybeUninit<AsyncFunc>
}

I don't know enough about the details of the desugarring to know why the dynamic dispatch is necessary, esp given that this is fine:

struct AsyncFunc {
    recursive: MaybeUninit<Pin<Box<AsyncFunc>>>
}

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.