Calling self functions in async

Hi! So I'm learning how to deal with async tasks and try to understand how to make them work. So far most of the issues have been solved by wrapping variables in an Arc<Mutex> for spawning them in a separate thread. The problem comes when I try to call a method from self containing a generic.

So for example (this is a minimal example to reproduce my case, it's not the actual code I'm working in), let's say I have this struct (I'm currently using tokio, but I assume the issue is not specific to the library):

struct MyStruct<B> {
    other: B
}

impl<B: std::fmt::Display> MyStruct<B> {
    async fn print_b(&self) {
        println!("{}", self.other);
    }

    async fn call_async(&self) {
        tokio::spawn(async move {
            self.print_b().await;
        });
    }
}

I'm obviously getting the error:

future cannot be sent between threads safely
future created by async block is not `Send`

The error makes sense, as we don't have any way to know that B implements Send, and actually it doesn't have to. But I'm having a lot of trouble figuring out how should I solve this. So is there a way to solve this in a more or less elegant way?

You can just add + Send to the impl block. Of course, once you do that, you'll run into trouble with having that tokio::spawn be inside the method. I have a draft of an article which you may find helpful, even if its still a draft: Actors with Tokio

1 Like

Thanks! Yeah I thought about adding + Send to B but the problem then is that I'd have to manually implement Send for any struct I use, right?

I'll check your article now, thanks!

The Send trait is an auto-trait, which means that it is automatically implemented for any type for which every field is Send.

1 Like

Oh gotcha! Thanks!

One follow up question: I guess then there's no way to do it with a type that doesn't implement Send then

No of course, if the type is not Send, you cannot send it to other threads. That's what Send means.