How to await trait function in a Box

Hello,

I'm beginning with rust async code. I have to manipulate objects by trait interface, so I boxed them.

But when I want to await trait function, I see that my Trait cannot be shared between threads safely. Example code:

Cargo.toml

[dependencies]
futures = "0.3.8"
async-trait = "0.1.42"

[dependencies.async-std]
version = "1.8.0"
features = ["unstable"]

main.rs

use async_std::task;
use async_trait::async_trait;

#[async_trait]
trait MyTrait {
    async fn job(&self) {
        println!("Hello, world !")
    }
}

struct MyStruct;
impl MyTrait for MyStruct {}

fn main() {
    let my_trait_in_box: Box<dyn MyTrait> = Box::new(MyStruct{});
    task::block_on(my_trait_in_box.job());
}

Error:

error[E0277]: `dyn MyTrait` cannot be shared between threads safely
  --> src/main.rs:16:36
   |
16 |     task::block_on(my_trait_in_box.job());
   |                                    ^^^ `dyn MyTrait` cannot be shared between threads safely
   |
   = help: the trait `Sync` is not implemented for `dyn MyTrait`

How can i deal with that ? (i don't know how to implement Sync)

Change the box to Box<dyn MyTrait + Send + Sync>, or change the trait to

#[async_trait]
trait MyTrait: Send + Sync {
    async fn job(&self) {
        println!("Hello, world !")
    }
}

The issue is not that the struct doesn't implement Sync, rather its because you told the compiler to forget about it by casting it to a dyn MyTrait.

1 Like

Send and Sync are only marker traits, in this case you do not need to do anything special to implement them, because they are automatically derived for your MyStruct.

You will only need to tell the Rust compiler that everything that implements your trait MyTrait will always have these markers:

#[async_trait]
trait MyTrait : Send + Sync {
    async fn job(&self) {
        println!("Hello, world !")
    }
}

See the docs of #[async_trait], mainly the section on dyn traits:

1 Like

Thank you all for all of this !

And the last solution, although not recommended when starting, is to use #[async_trait(?Send)] on the trait.