Reducing boilerplate in the "clone to Box" pattern


#1

I’m working on some code that uses dynamic polymorphism extensively. To clone trait instances I’ve end up using many copies of the “clone to Box” pattern suggested in various places (SO: “How to clone a struct storing a trait object?”, users.rust-lang: “Is it possible to clone a boxed trait object?”), viz.:

trait Trait: TraitClone {}

trait TraitClone {
    fn clone_to_box(&self) -> Box<Trait>;
}

impl<T> TraitClone for T where T: 'static + Trait + Clone {
    fn clone_to_box(&self) -> Box<Trait> {
        Box::new(self.clone())
    }
}

impl Clone for Box<Trait> {
    fn clone(&self) -> Box<Trait> {
        self.clone_to_box()
    }
}

#[derive(Clone)]
struct Impl {}
impl Trait for Impl {}

As I say I have many uses of this pattern. Each struct that implements Trait just needs a #[derive(Clone)], which is really slick; but every Trait needs a sibling trait and two impl blocks duplicated, which I’d like to improve.

Generic CloneToBox

I managed to write a generic trait CloneToBox<T> to replace TraitClone:

trait CloneToBox {
    type Boxed;
    fn clone_to_box(&self) -> Box<Self::Boxed>;
}

impl<T> CloneToBox for T where T: Clone {
    type Boxed = T;
    fn clone_to_box(&self) -> Box<Self::Boxed> {
        Box::new(self.clone())
    }
}

trait Trait: CloneToBox {}

// Rest as before

I’m amazed that this compiles (see Rust playground), as with a plain generic type on CloneToBox (not an associated type) compilation fails citing a circular reference in Trait's supertraits.


This seems a little cleaner than my first approach and is shorter than the other implementations I’ve found while searching. Any thoughts on putting this in a crate or the standard library?


#2

Oops, I spoke too soon!

It seems impossible to write the type of Trait in the version that uses the generic CloneToBox supertrait.

#[test]
fn example() {
    // This doesn't compile with "missing associated type `Boxed` value"
    let t1: &Trait = &Impl {};
    // This compiles, but is not polymorphic over implementations of Trait
    let t2: &Trait<Boxed = Impl> = &Impl {};
    // This doesn't compile with "missing associated type `Boxed` value" on the
    // inner Trait, i.e. this
    //                      |
    let t3: &Trait<Boxed = Trait> = &Impl {};
}

Can anyone make this work generically? Any other approaches people have tried?


I also considered using a macro to declare and implement TraitClone in a DRY way, but haven’t started trying to write it yet.