How can one await a result of a boxed future?
According to the implementation:
impl<F> Future for Box<F>
where
F: Unpin + Future + ?Sized,
Boxed futures only implement the Future
trait when the future inside the Box
implements Unpin
.
Since your function doesn't guarantee that the returned future implements Unpin
, your return value will be considered to not implement Future
. You'll not able to await
it because your type is basically not a Future
.
The solution from @Stargateur, adding an explicit type boundary to the signature, works (Playground):
fn test() -> Box<dyn Future<Output = Result<bool, ()>> + Unpin>
If you are using futures-rs, there is a helper type BoxFuture
. You can use BoxedFuture
without explicitly stating Unpin
:
use futures::future::BoxFuture;
fn test() -> BoxFuture<'static, Result<bool, ()>> {
Box::pin(async { Ok(true) })
}
Playground
When it comes to Box
and future
, it almost always make sense to use Box::pin
instead of Box::new
:
use std::pin::Pin;
use futures::{future, Future};
fn test() -> Pin<Box<dyn Future<Output = Result<bool, ()>>>> {
Box::pin(future::ok(true))
}
async fn async_fn() -> bool {
test().await.unwrap()
}
The reason is quite interesting. Pin
has a blanket implementation for Unpin
:
impl<P> Unpin for Pin<P> where
P: Unpin,
And the Box<T>
inside it is unconditionally Unpin
:
impl<T> Unpin for Box<T> where
T: ?Sized,
So a Pin<Box<dyn Future>>
is a unpinned Future
. Everything works out, but why Box
itself doesn't? This is one place where Deref
gets in the way:
impl<T: ?Sized> Deref for Box<T> {
type Target = T;
}
await
expects an unpinned Future
, and the Box<dyn Future>
you created with Box::new
does contain a Future
. So it is auto-dereferenced and the Unpin
is lost unless you explicitly state it that way with Box<dyn Future + Unpin>
.
Edit: @ÖmerErden is right about why Box<dyn Future>
wouldn't work.