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:
@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.
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.)
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:
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!
}
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.
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.
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).
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.
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).
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.