#![feature(async_fn_in_trait)]
use std::future::Future;
trait HealthCheck:Send {
async fn check(self) -> bool;
}
fn spawn<F:Future>(f:F) where F:Send + 'static{}
fn start_health_check<H>(h:H)
where
H: HealthCheck + Send + 'static,
{
spawn(async move {
let f = h.check();
f.await;
});
}
The compiler says
future is not Send as it awaits another future which is not Send, await occurs here on type impl Future<Output = bool>, which is not Send
However, we say H satisfies Send, hence h is sendable. In the block, f is an opaque future type impl Future<Output = bool>, the compiler says this type does not implement Send. However, the future generated by HealthCheck::check almost only captures self which has been required to satisfy Send, why is the future not sendable? In contrast to the following example
async fn senable_one(v:i32)->bool{ // The future generated by this function is sendable
true
}
struct D;
impl D{
async fn also_sendable(&self)->bool{ // The future generated by this method is sendable
true
}
};
The futures in above are both sendable since i32 and D(and &D) are sendable. What reason does make the generated future from the trait method to be not sendable?
You have misunderstanding on the condition of Future being Send.
// `Foo` is `Send`
struct Foo(std::sync::Mutex<i32>);
impl HealthCheck for Foo {
// This future is not `Send`
async fn check(self) -> bool {
// `guard` is not Send and it crossed an await point.
let guard = self.0.lock().unwrap();
async {}.await;
*guard == 0
}
}
Do you mean we might use an unsendable value in the check method of the implementations of HealthCheck, so the compiler cannot assume all futures returned by check of implementations of HealthCheck are sendable?
fn spawn<F:Future>(f:F) where F:Send + 'static{}
fn show<F:Future+Default>(){
spawn(async move{
let f = F::default();
f.await;
});
}
The only difference is that even though every input types(i.e the types of the method's parameters) are sendable, however, the content in the method's body(in the implementation) is not guaranteed to not violate
value that is !Send is used across an await point
So, the compiler just assumes all futures generated from check are not sendable except we explicitly specify the ReturnedFuture: Send.