Clone Box<dyn Trait<'a,A>

I want to clone a Box<dyn Trait<'a,A>. This question is similar to:

How can I clone a Vec<Box>? How to clone a struct storing a boxed trait object?

I have coded a similar solution for my problem, but I'm working with generics and associated types, and I'm having problems putting all together.

I give an example of the code I'm struggling to compile:

trait CTrait<'c> {
    fn do_C(&self) -> &'c str;
}

trait BTrait<'c> {
    type C : CTrait<'c>;
    fn do_B(&self) -> &'c str;
}

trait ATrait<'c, C : CTrait<'c>>: CloneATrait {
    type B: BTrait<'c, C=C>;
    fn do_A(&self) -> &'c str;
}

trait CloneATrait {
    fn clone_box<'c, C : CTrait<'c>, B : BTrait<'c, C = C>>(&self) -> Box<dyn ATrait<'c,C,B=B>>;
}

impl<'c, C : CTrait<'c>, T> CloneATrait for T
where
    T: 'static + ATrait<'c,C> + Clone,
{
    fn clone_box(&self) -> Box<dyn ATrait<'c,C,B = T::B>> {
        Box::new(self.clone())
    }
}


impl<'c, C : CTrait<'c>, B : BTrait<'c, C = C>> Clone for Box<dyn ATrait<'c,C,B=B>> {
    fn clone(&self) -> Box<dyn ATrait<'c,C,B=B>> {
        self.clone_box()
    }
}


#[derive(Clone)]
struct MultiA<'c, B : BTrait<'c>> {
    comps: Vec<Box<dyn ATrait<'c,B::C,B=B>>>,
}

impl<'c, B : BTrait<'c>> MultiA<'c,B> {
    fn new(comps: Vec<Box<dyn ATrait<'c,B::C,B=B>>>) -> Self {
        Self {
            comps
        }
    }
}

impl<'c, B : BTrait<'c>> ATrait<'c,B::C> for MultiA<'c,B> {
    type B = B;
    fn do_A(&self)  -> &'c str{
        for a in &self.comps{
            a.do_A();
        }
        self.comps[0].do_A()
    }
}



fn main() {

}

I've already asked that question in Stackoverflow(/questions/73127086/clone-boxdyn-traita-a) (sorry I'm only allowed to put two links) but maybe I'm luckier in this rust dedicated forum.

My first impression is that you're trying to use a lot of borrows (and thus liftimes) in long-lived structures which probably should not be; for example you have

trait ATrait<'c, C : CTrait<'c>>: CloneATrait {
    type B: BTrait<'c, C=C>;
    fn do_A(&self) -> &'c str;
}

but then attempt

impl<'c, C : CTrait<'c>, T> CloneATrait for T
where
    T: 'static + ATrait<'c,C> + Clone,

However it T is 'static, how can it return some otherwise unconstrained &'c str from &self? 'c might as well be 'static at that point. More generally, if you have a lifetime-bound Box<dyn Trait + '_>, you may be better off with a &'_ dyn Trait.


My second thought is your attempted implementation is circular. Getting rid of that, compiler errors point out that your traits aren't object safe. Pushing a little further, your implementation for MultiA doesn't even have the right signatures.

I think you'll have better luck starting from scratch and explaining what you're trying to accomplish, on a practical and more concrete level. Even if I took the time to change your code until it compiled, I doubt it would be anything actually useful to you.

1 Like

Thank you @quinedot for your answer. The code snippet is a minimal example so it doesn't have the functionality of the whole code (and as you pointed out it might have further issues, I have corrected MultiA signatures). But the idea is:

TraitC is a container. It owns something (a String in the example) and can give a reference to this element. It has the more complex functionality.

TraitB is also a container. It also gives access to TraitC result so I only want to worry about the lifetime of do_C. TraitB implementors can choose the TraitC implementor that best fits their purpose (that's why I have an associated type there).

TraitA is a generator. It can generate TraitB Implementors. All of them using the same TraitC implementor.

MultiA owns a vector of TraitA implementors. It just concatenates the result of all of them.

My problem is that I need to clone TraitA implementors. I do not have problems with "standalone" implementors, they are working fine, but MultiA has a vector of boxed trait objects, that is what i'm struggling with.

If I follow your English I end up here. Maybe you can glean what you need from it, or point out how it falls short of what you need to do.

In cases where you have some kind of function or factory, or anything that is not mutated when it is used, it may be sufficient to use Arc<dyn Trait> instead of Box<dyn Trait>. Then the Arc is clonable (sharing the data it points to) even though the dyn isn't.

1 Like