Why `Copy` need `Clone` as trait bound?

Just for curiousness, why Copy trait need Clone trait by definition, even there are not sharing implementation.

I know Copy is bitwise and Clone can do arbitrary complicated things, and I agree they should not sharing them implementations defined by Clone. My question is, why Copy need Clone as trait bound as now we have?

Is that trait bound just over-constricted (due to some history reason?) or it's related with some important properties I'm not notice yet? A type with Copy but without Clone seem no problem with me -- at least better than may have two different implementations?

Any idea?

I think generally, they should share implementation, and they do if you derive the traits. In the manual example from the linked doc;

struct MyStruct;

impl Copy for MyStruct { }

impl Clone for MyStruct {
    fn clone(&self) -> MyStruct {
        *self
    }
}

the clone method returns *self, which it can only do because self implements Copy.

And I think in most cases, if the clone method needs to do anything more than that, it is probably an indicator that the type should not implement Copy.

3 Likes

The requirement reflects a logical truism, rather than some technical requirement: If it's trivial to make a perfect copy (i.e. Copy is implemented), then it is also possible by definition to make a logical copy (i.e. Clone). Enforcing this in the type system means that a T: Clone bound will cover all types that can be copied, whether it's bitwise or not.

8 Likes

Agree with you. But this trait Copy: Clone {} still give us a "just be careful" situation we should upholding manually. For example, A crate developer may break the rule due to not read the doc carefully.

Btw, I also admit it may not really important because we may just use #[derive(Clone, Copy)] every times when we want some type copiable.

Anyway thanks, I like to hear those consideration.

Edit:

I try to re-read what I'm talking about above. And I notice the "Clone / Copy inconsistent" is not due to trait Copy: Clone {} but "Clone not auto-implemented by complier when Copy exists". If it can happen it's good for consistence but also add complexity into complier as add a special rule. Maybe that is the reason?

I do agree that reading just the main of this bad example you would be surprised that the assert fails. Maybe a warning when doing anything more than just returning *self in the clone() method of a Copy type would be a good thing?

Clippy has the lint expl_impl_clone_on_copy, but what it does is insist on using derive(Clone), not the *self implementation.

1 Like

This post could be useful. It's from a related question I once asked. You could have a blanket implementation of Clone for types that are Copy, but it causes problems because of limitations in the trait system.

2 Likes

Yes, the barriers doing to that (like in @bradleyharden's link) are why there's this "you better not..." finger-wag instead of a compiler error. It would be hard to change now due to backwards compatibility. There are other similar examples like implementing PartialOrd in a non-deterministic or inconsistent way.

Also, if they were distinct, you'd probably wish you could write a generic that accepted Copy or Clone, or a blanket implementation that covered both, but you can't.

1 Like

I don't see how this could possibly be OK. You are allowed to bitwise-copy the type, but you are not allowed to take a reference and produce an owned value from it. That doesn't make sense. Copy means "copiable in a special way, specifically, using a trivial bitwise copy", whereas Clone is more general, it means "copiable by doing something that is potentially more complicated than a bitwise memcpy". Allowing the more special capability without the more general one would be logically inconsistent.

4 Likes

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.