Why can't Clone be derived here?

I'm studying standard library documentation and I'm stuck on Clone trait:

An example is a generic struct holding a function pointer. In this case, the implementation of Clone cannot be derived, but can be implemented as:

struct Generate<T>(fn() -> T);

impl<T> Copy for Generate<T> {}

impl<T> Clone for Generate<T> {
    fn clone(&self) -> Self {
        *self
    }
}

But why though? 'fn' as a primitive does implement 'Clone'. It is definitely possible to do, I guess it won't work as intended?

AFAIK, the derive macros will only attempt to derive, if all type parameters implement the trait as well.

So it works, but only if T: Clone (if I understand right), which is not what you want.

#[derive(Clone)]
struct Generate<T>(fn() -> T);

(Playground)


I think the docs are misleading here, and it should read instead:

An example is a generic struct holding a function pointer. In this case, the implementation of Clone can only be derived for all T: Clone but not for all T: Sized. However, it can be manually implemented as follows, such that the struct can be cloned even where T: !Clone:

1 Like

This blog post might give insight on how derive works exactly.

@jbe your playground example is proof that how the docs present, is just plain wrong confusing at best. I suspect the docs were not updated since Clone was implemented for fn() -> T. The docs need to find another example to make the point.

Here's the example expanded, in case the example wasn't clear.

Suggestion

In this case, the derived implementation of Clone will only apply for all T: Clone. However, it can be manually implemented as follows, such that the struct can be cloned for any T: Sized (even if T is not Clone).

  • (you can still derive Clone, there's bounds on the implementation is all)

  • (T: !Clone is probably going to mean T explicitly declared they'll never be Clone without a new major release, and not that T: Clone does not hold. It's not stabilized syntax either way.)

Thanks for the extension; my example didn't really demonstrate the problems.

I don't think that was the case, because the "solution" in the docs uses the fact that fn() -> T is Copy.

What I just noticed in that matter is that it's not even needed to tell the compiler how to copy or clone:

struct Generate<T>(fn() -> T);

impl<T> Copy for Generate<T> {}

impl<T> Clone for Generate<T> {
    fn clone(&self) -> Self {
        // Self(self.0) // this isn't even needed!
        *self
    }
}

(Playground) (except for the extra comment I made, it's the example from the docs as linked in the OP)

The Copy implementation requires a Clone implementation, but the Clone implementation is done in a way it relies on Self: Copy. Consider:

struct Generate<T>(fn() -> T);

impl<T> Clone for Generate<T> {
    fn clone(&self) -> Self {
        Self(self.0) // now we need this
        //*self
    }
}

(Playground)

So it's actually more wicked than I thought. :open_mouth:

Maybe something like:

An example is a generic struct holding a function pointer returning T. Using #[derive(Clone)] will only implement Clone if the type parameter T is also Clone, consider:

#[derive(Clone)]
struct Generate<T>(fn() -> T);

struct NonClone;

fn example(g: Generate<NonClone>) {
    let _ = g.clone(); // fails!
}

However, such a struct could implement Copy and Clone also for any T that are not Clone (because the inner function can be copied). It's possible to trivially implement Copy as long as there is also an implementation of Clone, which may rely on the type being Copy:

struct Generate<T>(fn() -> T);

struct NonClone;

impl<T> Copy for Generate<T> {}

impl<T> Clone for Generate<T> {
    fn clone(&self) -> Self {
        // Self(self.0) // this isn't even needed!
        *self
    }
}

fn example(g: Generate<NonClone>) {
    let _ = g.clone(); // works!
}

(Playground for last example)

But perhaps such wording/examples would be a bit long for the docs.

1 Like

What's wicked about it? That's the recommended way to implement clone when you're also copy in order to uphold the expected variant, as stated immediately above. More generally, implementing a supertrait in terms of a subtrait is a common pattern.

There's a lot of redundancy with the existing verbiage immediately above.

1 Like

That Copy requires a Clone implementation and that the particular Clone implementation relies on Self: Copy. It feels (infinitely) recursive but works because Copy is a language feature, I guess.

No, it's a common pattern like I said. You just have to implement both. The implementations can rely on each other. Copying doesn't call clone though, so there's no infinite recursion. (You can create infinite recursion if you want in the general case.)

It's not that different from a function calling itself, or two calling each other.

I'm on mobile but if no one else does, I can supply examples later.

1 Like

Yes, I understand. It just requires that a Clone implementation exists (Clone is a supertrait of Copy), but it isn't used for copying. I guess that's what made it a bit confusing to me (though it sort-of has been clear to me, but I never thought about it that much).

So maybe saying "wicked" was a bit extreme. I don't see any particular problem with the behavior, but it has been (at least to me) a bit surprising. I don't want to say it is surprising, just that it's "notable", which the docs of Copy have also noted there:

Clone is a supertrait of Copy, so everything which is Copy must also implement Clone. If a type is Copy then its Clone implementation only needs to return *self (see the example above).

This extra note isn't found on the page on Clone.

1 Like

Well, it's worded a little less direct, but it's there. It's the very section we're talking about.

More formally: if T: Copy, x: T, and y: &T, then let x = y.clone(); is equivalent to let x = *y;.
[...]

[code example using Copy]

1 Like

Another example from std is implementing PartialOrd when you're also Ord: PartialOrd.

A very general pattern is when you need some functionality for all implementors of Trait, and there's one canonical way to do it, but it can't be a default function body for some reason and you don't want to burden implementors with writing it out (or perhaps don't want to give them the opportunity to override the default implementation).

In particular this comes up when the canonical way to do it applies almost always, but not always, and you can't put the bound on the method in order to supply the default function body. E.g.:

trait Trait: DynClone {}
trait DynClone {
    fn dyn_clone<'s>(&self) -> Box<dyn Trait + 's> where Self: 's;
}

// This is the only reasonable thing to do if you're `Clone + Trait`.
//
// But it relies on you being `Clone` and thus `Sized`, and thus we
// can't make it a default function body without adding bounds which
// make it unapplicable to `dyn Trait` -- something we explicitly want.
//
// It also relies on the subtrait in order to do the unsizing coercion.
impl<T: Clone + Trait> DynClone for T {
    fn dyn_clone<'s>(&self) -> Box<dyn Trait + 's> where Self: 's {
        Box::new(self.clone())
    }
}

// Requires `dyn_clone` be available to `dyn Trait`
impl Clone for Box<dyn Trait + '_> {
    fn clone(&self) -> Self {
        (**self).dyn_clone()
    }
}

Wiithout the supertrait dance, every implementor of Trait would have to supply the dyn_clone body -- in hopefully a reasonable way (i.e. like our blanket implementation). With the above arrangement, any implementor of Trait who is also Clone need not even think about it.

Oh, and yes -- if you also have this:

impl Trait for Box<dyn Trait + '_> {}

Then it's very important that we wrote things this way:

        (**self).dyn_clone()

Because if we had wrote self.dyn_clone(), we would have infinitely recursed between <Box<dyn Trait + '_> as Clone>::clone and <Box<dyn Trait + '_> as DynClone>::dyn_clone.

Okay, I see the similarity here. I guess it's the same relationship between Clone and Copy, maybe with the exception that Copy doesn't require any method to be implemented (because copying is done by the compiler / on the language-level). But in other terms, it's the same relationship:

  • Copy requires Clone but doesn't use clone for its implementation. Instead, clone can be implemented in terms of copying.
  • Ord requires PartialOrd but doesn't use partial_cmp. Instead, partial_cmp can be implemented by calling cmp.

What do you mean with "not always"? In the example you gave, the dyn_clone method will always be the same due to a blanket implementation. But maybe I misunderstand something.

I think they mean "there are cases where the canonical way is impossible, but some other way is possible instead". In the dyn_clone case, that's bare dyn Trait which can't be Clone, so its DynClone implementation can't use the canonical Box::new(self.clone()) way.

I mean that you can't do either of these...

trait Trait {
    fn dyn_clone<'s>(&self) -> Box<dyn Trait + 's> where Self: 's {
        Box::new(<Self>::clone(self))
    }
}
// error[E0277]: the trait bound `Self: Clone` is not satisfied
trait Trait {
    // new bound                                                  vvvvvvv
    fn dyn_clone<'s>(&self) -> Box<dyn Trait + 's> where Self: 's + Clone {
        Box::new(<Self>::clone(self))
    }
}

impl Clone for Box<dyn Trait + '_> {
    fn clone(&self) -> Self {
        (**self).dyn_clone()
    }
}
// error: the `dyn_clone` method cannot be invoked on a trait object
//  --> src/lib.rs:9:18
//   |
// 9 |         (**self).dyn_clone()
//   |                  ^^^^^^^^^ this has a `Sized` requirement

...and the dyn_clone method is not universally the same despite the blanket implementation; the implementation for dyn DynClone provided by the compiler performs implicit downcasting (in the form of dynamic dispatch) in order to call <SomeErasedBaseType as DynClone>::dyn_clone.

That is, the supertrait pattern allows us to define the method for all T: Clone + Trait without a Clone bound on the method. Then the compiler supplies the different definition for dyn Trait, which is not Clone (or even Sized), and thus is not covered by the blanket implementation. It doesn't call <dyn Trait>::clone -- that doesn't exist -- it calls <_ as DynClone>::dyn_clone via a vtable method pointer.


Another example is manual supertrait upcasting (again because we can't provide a default body without Sized), like when you need to go from dyn Trait to dyn Any (so you can get runtime downcasting).

Yet another example is to have

trait BoxedTrait { fn boxed_bye(self: Box<Self>); }
trait Trait: BoxedTrait { fn bye(self) /* implicit `where Self: Sized` */ ; }

so you can similarly implement Trait for Box<dyn Trait>, even though <dyn Trait>::bye does not exist due to the implicit Sized bound.

It's just fine. It's in fact the idiomatic way of manually implementing Clone for a Copy type.

Why would it be? Supertraits shouldn't need to know about their subtraits. That would be a leaky abstraction. A supertrait shouldn't have to (and can't) document the behavior of its subtraits. That's the job of the documentation of the individual subtraits. If you want to find out what Copy is, read the docs for Copy, not for Clone.

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.