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

Sorry for the late reply. I have tried refactoring the code to avoid the problem but unfortunately I need a way to define this in a generic way. So I have though about a simpler example for the same problem.

ATrait is a generator that generates BTrait implementors.
MultiA is a concatenator of generators.
I need to clone generators.

This is the code:

trait BTrait {
  
}

trait ATrait<B : BTrait>: CloneATrait {
    fn do_A(&mut self) -> Vec<B>;
}

trait CloneATrait {
    fn clone_box<B : BTrait>(&self) -> Box<dyn ATrait<B>>;
}

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


impl< B : BTrait> Clone for Box<dyn ATrait<B>> {
    fn clone(&self) -> Box<dyn ATrait<B>> {
        self.clone_box()
    }
}


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

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

impl<B : BTrait> ATrait<B> for MultiA<B> {
    fn do_A(&mut self)  -> Vec<B>{
        let mut res : Vec<B> = Vec::new();
        for a in &self.comps{
            res.append(a.do_A());
        }
        res
    }
}






fn main() {

}

That works fine for a simple generator:

trait BTrait {
  
}

trait ATrait<B : BTrait> {
    fn do_A(&mut self) -> Vec<B>;
}


impl BTrait for usize{
    
}

impl BTrait for f64{
    
}

#[derive(Clone)]
struct SingleA {
}


impl ATrait<usize> for SingleA {
    fn do_A(&mut self)  -> Vec<usize>{
        vec![1,2,3]
    }
}

impl ATrait<f64> for SingleA {
    fn do_A(&mut self)  -> Vec<f64>{
        vec![1.0,2.0,3.0]
    }
}


fn main() {
    let mut t = SingleA{};
    <SingleA as ATrait<usize>>::do_A(&mut t);
    <SingleA as ATrait<f64>>::do_A(&mut t);
}

I have made good progress with this but I have a problem with lifetimes (Rust Playground)

trait CTrait<'c1,'c2> {
    fn do_C1(&self) -> &'c1 str;
    fn do_C2(&self) -> &'c2 str;
}

trait BTrait<'c1,'c2> {
    type C: CTrait<'c1,'c2>;
    fn do_B(&self) -> &Self::C;
}

trait ATrait<'c1,'c2, C: CTrait<'c1,'c2>> {
    type B: BTrait<'c1,'c2, C = C>;
    fn do_A(&self) -> Vec<Self::B>;
    fn clone_box(&self) -> Box<dyn ATrait<'c1,'c2, C, B = Self::B>>;
}

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

struct MultiA<'c1,'c2, B: BTrait<'c1,'c2>> {
    comps: Vec<Box<dyn ATrait<'c1,'c2, B::C, B = B>>>,
}

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

impl<'c1,'c2, B: BTrait<'c1,'c2>> Clone for MultiA<'c1,'c2, B> {
    fn clone(&self) -> Self {
        Self {
            comps: self.comps.iter().map(|a| a.clone_box()).collect(),
        }
    }
}

impl<'c1,'c2, B: BTrait<'c1,'c2> + 'static> ATrait<'c1,'c2, B::C> for MultiA<'c1,'c2, B> {
    type B = B;
    fn do_A(&self) -> Vec<B> {
        for a in &self.comps {
            a.do_A();
        }
        self.comps[0].do_A()
    }
    fn clone_box(&self) -> Box<dyn ATrait<'c1,'c2, B::C, B = B>> {
        Box::new(MultiA::clone(self))
    }
}

fn main() {}

It gives me the error

error: lifetime may not live long enough
  --> src/main.rs:50:9
   |
41 | impl<'c1,'c2, B: BTrait<'c1,'c2> + 'static> ATrait<'c1,'c2, B::C> for MultiA<'c1,'c2, B> {
   |      --- lifetime `'c1` defined here
...
50 |         Box::new(MultiA::clone(self))
   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ returning this value requires that `'c1` must outlive `'static`

error: lifetime may not live long enough
  --> src/main.rs:50:9
   |
41 | impl<'c1,'c2, B: BTrait<'c1,'c2> + 'static> ATrait<'c1,'c2, B::C> for MultiA<'c1,'c2, B> {
   |          --- lifetime `'c2` defined here
...
50 |         Box::new(MultiA::clone(self))
   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ returning this value requires that `'c2` must outlive `'static`

help: the following changes may resolve your lifetime errors
  |
  = help: replace `'c1` with `'static`
  = help: replace `'c2` with `'static`

error: could not compile `playground` due to 2 previous errors

I'm not sure what's the problem.

In case you didn't know, all trait objects have a "lifetime of applicability" (dyn Trait + '_). The idea is that it may only be valid to utilize the trait within a limited lifetime, depending on the erased type. The lifetime has various defaults in various positions and is usually elided, but sometimes these defaults can bite you. The default for a Box<dyn Trait> outside of a function body is 'static.

I didn't put a ton of thought into it, but I think the basic problem is that your Box<dyn ATrait<'c1, 'c2, C, B>> can only be valid for the smaller of 'c1 or 'c2, and given the default 'static lifetime of applicability, that would mean 'c1 and 'c2 have to be 'static.

You can track the smaller of the two lifetimes by having 'c1: 'union, 'c2: 'union and then use a dyn ATrait<...> + 'union. (I should have named it 'intersection probably, oops.)

That being said, even without this change, your playground is overusing generics (especially lifetime generics) in my estimation.

1 Like

I didn't know about the "lifetime of applicability" of trait objects but now I can partially understand my problems. I still don't get why by can only be valid the smallest of 'c1 or 'c2.

As you have said I probably misusing lifetime generics. I'm new to Rust. My real CTrait is more like:

struct HugeStruct1{
    
}

struct HugeStruct2{
    
}


trait CTrait<'c1: 'union, 'c2: 'union, 'union> {
    fn do_C1(&self) -> &'c1 HugeStruct1;
    fn do_C2(&self) -> &'c2 HugeStruct2;
}


trait CTraitAlt<'c> {
    fn do_C1(&self) -> &'c HugeStruct1;
    fn do_C2(&self) -> &'c HugeStruct2;
}


fn main() {}

The HugeStructs are heavy and are shared by lots of CTraits. It looked like a good idea that each reference has its lifetime. However, for my code it seems enough to share a lifetime as in CTraitAlt. In my case a lifetime is necessary because I need the results of the do_C1 and do_C2 to outlive its caller. What is more idiomatic CTrait or CTraitAlt?

When I saw the errors, I made an educated guess that the lifetime of applicability was problematic, and limited by the lifetimes involved. Under that assumption, there's nothing to distinguish 'c1 or 'c2 -- if one was making dyn _ + 'static invalid, the other one must do so too. There is no syntax for "the more restrictive of 'c1 and 'c2", so I introduced the new lifetime and constrained it to be valid for both -- effectively, at most the smaller of the two lifetimes. After that it was just a matter of mechanical substitution. After enough substitution, things compiled.


If you only use one lifetime, you won't need some lifetime to limit a set of otherwise unrelated lifetimes, so that will still be simpler. Or under a different lens, by having exactly one lifetime, you're forcing implementors to use the smallest of the set of lifetimes. Since you need that smallest lifetime anyway, and it's going to limit your dyn objects, and because people rightfully balk when they see something as convoluted as my latest playground... I'd say CTraitAlt is the likely more-idiomatic choice. Here's a single lifetime version.

It's too bad just not having lifetimes doesn't work for your use-case as it is much simpler yet. But as you say, it means you can't return a borrow longer than that of &self.

One alternative is to use shared ownership (Rc or Arc); then you could return something that acts roughly like a reference but has no lifetime limit beyond the contained type.

Another alternative is to not use traits and use concrete types instead. Lifetimes on structs tend to be more flexible (lifetimes on traits are invariant, where as the variance of structs is inferred). In place of dyn you would use enums. You do need to know the set of types ahead of time. I'm not sure it would actually be any simpler or nicer in this particular case.

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.