use std::sync::Arc; struct NoClone ; struct WrapArc (Arc); fn main () { let foo = WrapArc (Arc:: new (NoClone)); let foo_ = foo. clone (); }
Do you think this code should compile?
What about the following code:
struct AlwaysEq (T); impl PartialEq for AlwaysEq { fn eq (& self , _other: & Self ) -> bool { true } } impl Eq for AlwaysEq {} struct NotEq ; struct WrapAlwaysEq (AlwaysEq); fn assert_is_eq (_: impl Eq ) {} fn main () { let x = WrapAlwaysEq ( AlwaysEq (NotEq)); assert_is_eq (x); }
The second example is a bit far fetched, but you probably answered yes.
But neither do.
Why not?
The implementation of #[derive(Clone)] in the Rust compiler generates a Clone implementation with the following requirements on the derived type:
All fields must be Clone .
. All generic parameters must be Clone .
Can you spot the issue here? It's the latter requirement: we cannot just require all generic parameters to be Clone , as we cannot assume they are used in such a way that requires them to be cloned.^1
This applies to practically all builtin derive traits, such as Clone , PartialEq , Eq , or even Debug .
What can we do to fix this?
There are two solutions to this. Both require deleting that second requirement.
The hard way
We could create a Rust RFC, hopefully not bikeshed it to death, and get it stabilized in the next Rust edition as it is a breaking change.^2
This would take 4+ years to stabilize and be available to everyone. That sucks, but is the correct thing to do in the long-term.
The quick way
We can just write our own macro that generates the following code:
struct WrapArc (Arc); impl Clone for WrapArc where Arc: Clone , { }
This does the job correctly.
And it's not even hard to do. I know people who do this internally in their company codebases - it's not much code.
So I've opened an issue about replicating the builtin derive traits in a less restrictive and thus correct way in the derive_more crate's GitHub repository. The reason I chose this crate is because it already has a lot of users and is the main place for derive implementations.
Replicating already-existing behaviour of the std may not be in the scope of the crate, which is a perfectly fine stance to take. If that doesn't get accepted, I'll probably create my own crate and release it on crates.io.
Stay tuned, I'll update this blog post.