# [derive(Clone)] Is Broken

Core issue with #[derive(Clone)]

  • Thread centers on the fact that #[derive(Clone)] adds bounds like T: Clone on generic types, even when only the fields need to be Clone.
  • Example: struct Foo<T>(Arc<T>) is derive-failing today because T: Clone is required, though Arc<T>: Clone needs no such bound.
  • This also affects other derivable traits (Debug, PartialEq, etc.), making derive less useful for many generic types and for phantom parameters.

Historical and type-system constraints

  • Linked design notes explain the original choice: “perfect derive” (deriving from field requirements) used to be blocked by:
    • Need to allow cyclic trait reasoning (like for auto traits Send/Sync), which is hard to keep sound.
    • A semver hazard: derived bounds would silently change when private fields change (e.g., switching from Rc<T> to T in a list type alters when List<T>: Clone holds).
  • Some argue this is now mostly a policy/semver question, not a hard technical blocker.

Workarounds and proposed improvements

  • Several crates implement “perfect derive” or allow explicit where-like annotations on derive to override bounds, sometimes with escape hatches for cycles.
  • Suggestions:
    • Allow explicit bound syntax inside derive (e.g. #[derive(Clone(bounds(Arc<T>: Clone)))]).
    • Add attributes to exclude fields from auto-derives (#[noderive(Clone)] style).
    • Keep derive simple in std and rely on crates for advanced behavior.

Developer experience and error messages

  • Multiple commenters report being badly confused the first time they hit this, especially when all fields are obviously Clone but the type isn’t.
  • Current diagnostics tend to point at the inner type (“implement Clone for T”), often suggesting the wrong fix.
  • There is a concrete request to improve the error message by explaining that derive inserted overly restrictive bounds and suggesting a manual impl as a fix.

Comparisons and broader language debates

  • Haskell’s deriving was cited; correction: Haskell effectively does “perfect derive” by constraining only field types.
  • Long subthreads debate Rust vs Haskell features (strictness, linear/affine types) and Rust vs C++ complexity, macros, and ecosystem bloat.
  • Some see Rust derive as a useful convenience whose edge cases don’t justify extra complexity; others see this quirk as an unnecessary “sharp edge” that undercuts Rust’s usual ergonomics.

LLMs and boilerplate

  • One branch argues that LLMs can generate and maintain manual impls, reducing the need for richer derive mechanisms.
  • Others are skeptical, pointing to hallucinations, overconfident wrong answers, and the risk of developers not recognizing subtle mistakes.