[solved] Is it possible to clone a boxed trait object?

Suppose we have the following:

trait Foo { }
fn bar(baz: Box<Foo>) {
    let qux = baz.clone();
}

This will fail to compile with an error indicating that clone cannot be found for Box<Foo>.

Is there any way to require that implementers of Foo must also implement Clone such that all Box<Foo> can be cloned or something along those lines?

3 Likes

Only if Foo is defined as Foo: Clone or the trait object is Box<Foo + Clone>, unless I'm forgetting something.

1 Like

You must have an implementation of Clone for Box<Foo>. Foo should not inherit Clone.

2 Likes

I tried those two methods, here are the results:

trait Foo: Clone { }
fn bar(baz: Box<Foo>) {
    let qux = baz.clone();
}

This works in the test case provided above. Unfortunately, I am also doing:

impl<'a> PartialEq<Foo + 'a > for Foo + 'a {
    ...
}

When combined with the previous code I get an error indicating that Foo can no longer be made into an object.

With:

trait Foo { }
fn bar(baz: Box<Clone + Foo>) {
    let qux = baz.clone();
}

I receive an error because only builtin traits can be used as closure or object bounds.

I'm currently experimenting with workarounds such as changing the definition of Foo to:

trait Foo {
    fn box_clone(&self) -> Box<Foo>;
}

I feel that this solution isn't very elegant though.

1 Like

Using box_clone() is the approach that works. Note that if you add that to the trait and use that to impl Clone for Box<Foo>, you can clone it as wanted.

1 Like

Thank you for your help bluss.

Here is the final code for others who may encounter this issue:

trait Foo {
    fn box_clone(&self) -> Box<Foo>;
}

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

#[derive(Clone)]
struct Bar;

impl Foo for Bar {
    fn box_clone(&self) -> Box<Foo> {
        Box::new((*self).clone())
    }
}

#[test]
fn it_works() {
    let baz = Box::new(Bar) as Box<Foo>;
    let qux = baz.clone();
}
25 Likes

Here is an improved solution for anyone who comes across this. I changed BoxClone to CloneFoo because it is specific to Foo. Also you don't have to re-implement CloneFoo for every derived struct.

trait Foo: CloneFoo {}

#[derive(Clone)]
struct Bar;

impl Foo for Bar {}

trait CloneFoo {
    fn clone_foo<'a>(&self) -> Box<dyn Foo>;
}

impl<T> CloneFoo for T
where
    T: Foo + Clone + 'static,
{
    fn clone_foo(&self) -> Box<dyn Foo> {
        Box::new(self.clone())
    }
}

impl Clone for Box<dyn Foo> {
    fn clone(&self) -> Self {
        self.clone_foo()
    }
}
8 Likes

There is also dyn-clone.

4 Likes