Deep copy value of Arc<Mutex<SomeTrait>>>?

In my main I define a struct which has a trait implemented. This struct I pass to different functions. I am trying to get a unique instance of the struct in each function. But because Arc/Mutex is used, that of course is not possible.

I understand why it is not possible, Arc just makes a new pointer to the same data in memory. So changing something in one function also alters it in the other functions getting the variable as parameter.

use std::sync::Arc;
use tokio::sync::Mutex;

pub trait Animal {
    fn new() -> Self where Self: Sized;
    fn set_name(&mut self, name: String);
    fn get_name(&self) -> String;
}

pub struct Cat {
    name: String,
}

impl Animal for Cat {
    fn new() -> Self {
        Cat {
           name: "".to_string(), 
        }
    }

    fn set_name(&mut self, name: String) {
        self.name = name;
    }

    fn get_name(&self) -> String {
        self.name.to_string()
    }

}

#[tokio::main]
async fn main() {
    let mut animal : Cat = Animal::new();
    animal.set_name("Garfield".into());
    println!("Original name: {}", animal.name);
    let animal = Arc::new(Mutex::new(animal));

    func1(animal.clone()).await;
    func2(animal.clone()).await;
}

pub async fn func1(animal: Arc<Mutex<dyn Animal>>) {
    let clone = animal.clone();
    let mut guard = animal.lock().await;

    guard.set_name("Foobar".into());
    println!("After change: {}", guard.get_name());
}

pub async fn func2(animal: Arc<Mutex<dyn Animal>>) {
    let clone = animal.clone();
    let guard = clone.lock().await;
   
    // Check if still Garfield.
    println!("Still Garfield? {}. No...", guard.get_name());
}

pub async fn func3() {
    // Only way to make a new instance seems to create it manually.
    let mut animal : Cat = Animal::new();
    animal.set_name("Garfield".into());
}

I was looking for a way to be able to copy the data of the animal in one function. Change it only in the scope of that function without affecting the instances of animal in the other functions.

This question gave some answers but no valid one I guess due to the complexity with mutex.

So currently I can only do let mut animal : Cat = Animal::new(); in all the functions who want a unique value for Animal. But the problem is that I then would have to define the struct implementing Animal everywhere. The reason I was using a trait is so the programmer can change what version of Animal is used by only changing it on one line in the code.

I guess I could define a type, so the coder can change it there, but that is not the most elegant solution I think.

I wrote about a related pattern (cloneable Box<dyn Trait>) here. But some differences are

  • Arc<_> and tokio::Mutex are not fundamental so there some orphan rules to consider
  • tokio::Mutex locks in an async manner

The latter is relevant because you need to access the unerased value in order to clone it, which means awaiting or blocking on the mutex lock.

And here's what I came up with.

pub trait CloneAnimal {
   fn clone_animal<'s>(&self) -> Arc<Mutex<dyn Animal + 's>> where Self: 's;
}

impl<T: Clone + Animal> CloneAnimal for T {
   fn clone_animal<'s>(&self) -> Arc<Mutex<dyn Animal + 's>> where Self: 's {
       Arc::new(Mutex::new(self.clone()))
   }
}

pub trait AsyncCloneAnimal {
    async fn async_clone<'s>(&self) -> Arc<Mutex<dyn Animal + 's>> where Self: 's;
}

impl<T: ?Sized + CloneAnimal> AsyncCloneAnimal for Arc<Mutex<T>> {
    async fn async_clone<'s>(&self) -> Arc<Mutex<dyn Animal + 's>> where Self: 's {
        (*(self.lock().await)).clone_animal()
    }
}

You need a supertrait bound (so the compiler will implement CloneAnimal for dyn Animal):

pub trait Animal: CloneAnimal {

Usage:

    func1(animal.async_clone().await).await;
1 Like

I tried running your code but got an error:

error[E0706]: functions in traits cannot be declared `async`
  --> src/algotester3.rs:22:5
   |
22 |     async fn async_clone<'s>(&self) -> Arc<Mutex<dyn Animal + 's>> where Self: '...
   |     -----^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
   |     |
   |     `async` because of this
   |
   = note: `async` trait functions are not currently supported
   = note: consider using the `async-trait` crate: https://crates.io/crates/async-trait
   = note: see issue #91611 <https://github.com/rust-lang/rust/issues/91611> for more information

error[E0195]: lifetime parameters or bounds on method `async_clone` do not match the trait declaration
  --> src/algotester3.rs:22:25
   |
18 |     async fn async_clone<'s>(&self) -> Arc<Mutex<dyn Animal + 's>> where Self: ...
   |     -----               ----                                                   -- this bound might be missing in the impl
   |     |                   |
   |     |                   lifetimes in impl do not match this method in trait
   |     this bound might be missing in the impl
...
22 |     async fn async_clone<'s>(&self) -> Arc<Mutex<dyn Animal + 's>> where Self: '...
   |                         ^^^^                                       -------------- this `where` clause might not match the one in the trait
   |                         |
   |                         lifetimes do not match method in trait
use std::sync::Arc;
use tokio::sync::Mutex;
use async_trait::async_trait;

#[async_trait]
pub trait CloneAnimal {
   fn clone_animal<'s>(&self) -> Arc<Mutex<dyn Animal + 's>> where Self: 's;
}

impl<T: Clone + Animal> CloneAnimal for T {
   fn clone_animal<'s>(&self) -> Arc<Mutex<dyn Animal + 's>> where Self: 's {
       Arc::new(Mutex::new(self.clone()))
   }
}

#[async_trait]
pub trait AsyncCloneAnimal {
    async fn async_clone<'s>(&self) -> Arc<Mutex<dyn Animal + 's>> where Self: 's;
}

impl<T: ?Sized + CloneAnimal> AsyncCloneAnimal for Arc<Mutex<T>> {
    async fn async_clone<'s>(&self) -> Arc<Mutex<dyn Animal + 's>> where Self: 's {
        (*(self.lock().await)).clone_animal()
    }
}

// -----

// Added supertrait bound
pub trait Animal: CloneAnimal {
    fn new() -> Self where Self: Sized;
    fn set_name(&mut self, name: String);
    fn get_name(&self) -> String;
}

// Added derive
#[derive(Clone)]
pub struct Cat {
    name: String,
}

impl Animal for Cat {
    fn new() -> Self {
        Cat {
           name: "".to_string(), 
        }
    }

    fn set_name(&mut self, name: String) {
        self.name = name;
    }

    fn get_name(&self) -> String {
        self.name.to_string()
    }

}

#[tokio::main]
async fn main() {
    let mut animal : Cat = Animal::new();
    animal.set_name("Garfield".into());
    println!("Original name: {}", animal.name);
    let animal = Arc::new(Mutex::new(animal));

    func1(animal.async_clone().await).await;
    func2(animal.async_clone().await).await;
}

pub async fn func1(animal: Arc<Mutex<dyn Animal>>) {
    let clone = animal.async_clone().await;
    let mut guard = animal.lock().await;

    guard.set_name("Foobar".into());
    println!("After change: {}", guard.get_name());
}

pub async fn func2(animal: Arc<Mutex<dyn Animal>>) {
    let clone = animal.async_clone().await;
    let guard = clone.lock().await;
   
    // Check if still Garfield.
    println!("Still Garfield? {}. No...", guard.get_name());
}

pub async fn func3() {
    // Only way to make a new instance seems to create it manually.
    let mut animal : Cat = Animal::new();
    animal.set_name("Garfield".into());
}

Edit:
Adding #[async_trait] to the impl as well gives the following error:

error: future cannot be sent between threads safely
  --> src/algotester3.rs:22:83
   |
22 |       async fn async_clone<'s>(&self) -> Arc<Mutex<dyn Animal + 's>> where Self: 's {
   |  ___________________________________________________________________________________^
23 | |         (*(self.lock().await)).clone_animal()
24 | |     }
   | |_____^ future created by async block is not `Send`
   |
note: captured value is not `Send` because `&` references cannot be sent unless their referent is `Sync`
  --> src/algotester3.rs:22:31
   |
22 | ...n async_clone<'s>(&self) -> Arc<Mutex<dyn Animal +...
   |                       ^^^^ has type `&Arc<tokio::sync::Mutex<T>>` which is not `Send`, because `Arc<tokio::sync::Mutex<T>>` is not `Sync`
   = note: required for the cast from `Pin<Box<{async block@src/algotester3.rs:22:83: 24:6}>>` to `Pin<Box<...>>`
   = note: the full name for the target type has been written to '/Users/niel/Sites/keyrock/rust-api/target/debug/deps/algotester3-51ba62b3b1f57961.long-type-12765469092035116698.txt'
help: consider further restricting this bound
   |
21 | impl<T: ?Sized + CloneAnimal + std::marker::Send> AsyncCloneAnimal for Arc<Mutex<T>> {
   |

I got it to work with a few edits! Thanks:

use std::sync::Arc;
use tokio::sync::Mutex;
use async_trait::async_trait;

pub trait CloneAnimal {
   fn clone_animal<'s>(&self) -> Arc<Mutex<dyn Animal + 's>> where Self: 's;
}

impl<T: Clone + Animal> CloneAnimal for T {
   fn clone_animal<'s>(&self) -> Arc<Mutex<dyn Animal + 's>> where Self: 's {
       Arc::new(Mutex::new(self.clone()))
   }
}

#[async_trait]
pub trait AsyncCloneAnimal {
    async fn async_clone<'s>(&self) -> Arc<Mutex<dyn Animal + 's>> where Self: 's;
}

#[async_trait]
impl<T: ?Sized + CloneAnimal + std::marker::Send> AsyncCloneAnimal for Arc<Mutex<T>> {
    async fn async_clone<'s>(&self) -> Arc<Mutex<dyn Animal + 's>> where Self: 's {
        (*(self.lock().await)).clone_animal()
    }
}

// -----

// Added supertrait bound
#[async_trait]
pub trait Animal: CloneAnimal + Send {
    fn new() -> Self where Self: Sized;
    fn set_name(&mut self, name: String);
    fn get_name(&self) -> String;
}

// Added derive
#[derive(Clone)]
pub struct Cat {
    name: String,
}

impl Animal for Cat {
    fn new() -> Self {
        Cat {
           name: "".to_string(), 
        }
    }

    fn set_name(&mut self, name: String) {
        self.name = name;
    }

    fn get_name(&self) -> String {
        self.name.to_string()
    }

}

#[tokio::main]
async fn main() {
    let mut animal : Cat = Animal::new();
    animal.set_name("Garfield".into());
    println!("Original name: {}", animal.name);
    let animal = Arc::new(Mutex::new(animal));

    func1(animal.async_clone().await).await;
    func2(animal.async_clone().await).await;
}

pub async fn func1(animal: Arc<Mutex<dyn Animal>>) {
    let clone = animal.async_clone().await;
    let mut guard = animal.lock().await;

    guard.set_name("Foobar".into());
    println!("After change: {}", guard.get_name());
}

pub async fn func2(animal: Arc<Mutex<dyn Animal>>) {
    let clone = animal.async_clone().await;
    let guard = clone.lock().await;
   
    // Check if still Garfield.
    println!("Still Garfield? {}. No...", guard.get_name());
}

pub async fn func3() {
    // Only way to make a new instance seems to create it manually.
    let mut animal : Cat = Animal::new();
    animal.set_name("Garfield".into());
}

Could you elaborate bit on your answer please?

The required edits were probably do to something the macros do which I don't know about offhand; I'm glad you figured it out.

I'm going to be lazy about being as lifetime-flexible as possible in the rest of this reply for the sake of brevity / clearer code.

The basic idea is that you need to downcast to the base type in order to "deep clone" a dyn Trait. Because you need to get at the base type's Clone implementation. But you don't want to do this fallibly,[1] so instead you want the compiler to infallibly downcast for you, via the dyn Trait vtable, as it does for method receivers.

As for the method signatures, you can't have

fn clone(&self) -> Self
// for `dyn Trait`:
fn clone(self: &dyn Clone) -> dyn Clone

because dyn Trait is not Sized, so instead you have

fn trait_clone(&self) -> Container<dyn Trait>

As getting that container is your goal anyway.

So we start with this trait:

pub trait CloneAnimal {
   fn clone_animal(&self) -> Arc<Mutex<dyn Animal>>;
}

We know how to implement it if T: Clone + Animal + Sized: Just clone and coerce. We write this so that consumers of these traits won't have to.

// `T: Sized` implicitly
// `'static` now due to being lazy about lifetimes
impl<T: Clone + Animal + 'static> CloneAnimal for T {
   fn clone_animal(&self) -> Arc<Mutex<dyn Animal>> {
       Arc::new(Mutex::new(self.clone()))
   }
}

The compiler supplies impl CloneAnimal for dyn CloneAnimal automatically. However, we want this to be available for dyn Animal, so we add a supertrait bound:

pub trait Animal: CloneAnimal {

Now the compiler also supplies impl CloneAnimal for dyn Animal.

How does this impact implementors of Animal? If they implement Clone, not at all, due to our blanket implementation -- which is why I broke it out into another trait. Another option would be to just make clone_animal a method of Animal. But then you can't provide the implementation; all implementors have to supply their own repetitive implementation.[2] More flexibility but more boilerplate.


At this point, if Container<_> was our own type or fundamental like Box, and if the async considerations didn't exist, we could

impl Clone for Container<dyn Animal> {
    fn clone(&self) -> Self {
    //   vvvvvv drill down to `dyn Animal` and call the compiler
        (**self).clone_animal()  // provided implementation, which
                                 // infallibly downcasts to the base
                                 // type and calls it's implementation
    }
}

But this isn't an option since Arc (and tokio::Mutex) aren't local or fundamental, even before considering the async nature of the Mutex.

If it wasn't for the async considerations, or if we were ok blocking, we could still

impl CloneAnimal for Arc<Mutex<dyn Animal>> {
    fn clone_animal(&self) -> Arc<Mutex<dyn Animal>> {
        // or whatever the syntax is
        (*block_on(self.lock())).clone_animal()
    }
}

// Or alternatively
impl Clone for NewType<Arc<Mutex<dyn Animal>>> ...

But instead I decided to make an async version of CloneAnimal.

pub trait AsyncCloneAnimal {
    async fn async_clone(&self) -> Arc<Mutex<dyn Animal>>;
}

And this is straightforward to implement for Arc<Mutex<T: ?Sized + CloneAnimal>> (which includes Arc<Mutex<dyn Animal>> in addition to Arc<Mutex<Cat>>, etc).


Something I didn't address at all in either comment is auto-traits. You may want your dyn Animals to be dyn Animal + Send or + Sync or both, or perhaps put those bounds on the trait itself.


  1. or rather, make implementors do it fallibly, if you don't know all the implementors ↩︎

  2. You can only provide the default body if Self: Clone, which requires Self: Sized (which you also need to unsize coerce) -- so putting that bound on the trait or method makes the trait non-object safe or the method not-dyn dispatchable, either of which defeats the point. ↩︎

1 Like

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.