Update Trait object behind Arc once

Hello everyone,

use std::sync::Arc;

fn send_to_thread(obj: Arc<dyn Trait>) {}

trait Trait {
    fn update(&mut self);
}
struct Foo{}
impl Trait for Foo {
    fn update(&mut self){}
}


pub fn new_obj() -> Arc<dyn Trait> {
    Arc::new(Foo{})
}

fn main() {
   let mut foo: Arc<dyn Trait> = new_obj();
   foo.update(); // Obviously can't mutate behind Arc
   send_to_thread(foo);
}

Here's the deal. I need to

  1. Create a dyn Trait.
  2. Update(initialize) it once.
  3. Sent to threads.

My options:

  1. Fully initialize object in new_obj - Possible, but new_obj would have been greatly complicated.
  2. Return Box<dyn Trat> but since I need an Arc, converting to Arc needs to reallocate. Not good.
  3. Wrap it in Arc<Mutex> - An overkill, I'm not going to mutate object in threads.

I'm seeking to have the least overhead because it's in a hot loop.
Appreciate any advice.

Since the Arc has not yet been cloned, you can use Arc::get_mut:

Arc::get_mut(&mut foo).unwrap().update();
2 Likes

Oh man, all this time I thought Arc is not mutable no matter what :smile: I should've checked the docs, thank you!

An alternative approach is to defer creating the trait object until it’s fully initialized:

use std::sync::Arc;

fn send_to_thread(obj: impl Trait)->Arc<dyn Trait> { Arc::new(obj) }

trait Trait: 'static {
    fn update(&mut self);
}
struct Foo{}
impl Trait for Foo {
    fn update(&mut self){}
}


pub fn new_obj() -> impl Trait {
    Foo{}
}

fn main() {
   let mut foo = new_obj();
   foo.update(); // Obviously can't mutate behind Arc
   let foo_ref = send_to_thread(foo);
}

(Playground)

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.