From fa63313d17b56b7e9b5d6f8fb2c3cbd7e7a064ea Mon Sep 17 00:00:00 2001 From: Ben Striegel Date: Thu, 26 Mar 2015 20:06:41 -0400 Subject: [PATCH] Automatically derive certain traits when more fundamental traits are derived --- text/0000-derive-copy-and-clone.md | 44 ++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) create mode 100644 text/0000-derive-copy-and-clone.md diff --git a/text/0000-derive-copy-and-clone.md b/text/0000-derive-copy-and-clone.md new file mode 100644 index 00000000000..0a504321a60 --- /dev/null +++ b/text/0000-derive-copy-and-clone.md @@ -0,0 +1,44 @@ +- Feature Name: derive-implied-traits +- Start Date: 2015-03-26 +- RFC PR: (leave this empty) +- Rust Issue: (leave this empty) + +# Summary + +This RFC proposes three related changes: + +1. When `#[derive(Copy)]` is placed on a type, that type automatically recieves a `#[derive(Clone)]` attribute. + +2. When `#[derive(Eq)]` is placed on a type, that type automatically receives a `#[derive(PartialEq)]` attribute. + +3. When `#[derive(Ord)]` is placed on a type, that type automatically recieves a `#[derive(PartialOrd)]` attribute. + +# Motivation + +In each of these three cases, one of each pair of traits is more "fundamental" than the other, such that it is reasonable to assume that no user wants to derive one without also deriving the other. + +It is evident and uncontroversial that `Copy` should imply `Clone` (https://github.com/rust-lang/rust/pull/23860). In the case of `Copy`, it is a common pitfall that library authors will derive `Copy` for their types and yet forget to derive `Clone` as well. When this happens it is a strict loss of expressiveness which makes the type in question ineligible to participate in generic programming that involves cloning, despite the fact that `Copy` effectively denotes types for whom a clone is but a `memcpy`. Past remedies to this problem have suggested a blanket impl of `Clone` for all `T: Copy` (https://github.com/rust-lang/rust/issues/17884), however modern consensus seems to believe that this approach is not feasible. Instead, we propose that any derived implementation of `Copy` automatically receive an autogenerated implementation of `Clone` in order to free library authors from this all-too-easy oversight. Finally, if the compiler knows that a type implements `Copy`, then there exist opportunities for the compiler to insert an optimized `Clone` implementation that consists entirely of `*self`. + +In the case of `Eq` and `Ord`, the motivation is different. Implementors of either of these traits must first implement their partial versions, which means that no user can accidentally omit them. However, it is our subjective experience that no user who derives `Eq` will have manually implemented `PartialEq`; likewise for `Ord` and `PartialOrd`. Therefore this aspect of this RFC is solely to improve ergonomics, and should be considered secondary in importance to the issue of `Copy` and `Clone`. + +# Detailed design + +The `derive` syntax extension must be modified to accomodate these hardcoded rules. The compiler must be able to accept both `#[derive(Copy, Clone)]` and `#[derive(Copy)]`, the latter of which will implicitly insert a derived implementation of `Clone`. Like wise the compiler must accept both `#[derive(Eq)]` and `#[derive(PartialEq, Eq)]`, as well as both `#[derive(Ord)]` and `#[derive(PartialOrd)]`. Despite not appearing in the source, the automatically inserted implementations must be visible to rustdoc. + +An implementation of this RFC can be seen here: https://github.com/rust-lang/rust/pull/23905 + +# Drawbacks + +Makes certain derived traits "special", forming a pseudo-inheritance hierarchy of sorts. + +Rustdoc will show implementations of traits with no direct origin in the source. + +# Alternatives + +The most straightforward alternative would be to accept only the `Copy`/`Clone` aspect of this RFC, as it is concerned with library correctness (in the "const correctness" sense) whereas the `Ord`/`PartialOrd` and `Eq`/`PartialEq` cases are merely for ergonomics. + +If the above alternative is desired, then it may make sense, for consistency's sake, to cause the compiler to return an error when it encounters `#[derive(Copy)]`, with a message demanding that the user modify the attribute to `#[derive(Copy, Clone)]`. This would address the drawback of there being an unclear origin for the `Clone` trait when viewed from rustdoc. It would also have symmetry with the demand for `#[derive(PartialOrd, Ord)]`, again assuming that the alternative from the prior paragraph is desired. + +# Unresolved questions + +Is it reasonable to assume that no user who automatically derives `Eq`/`Ord` has manually implemented `PartialEq`/`PartialOrd`? If this assumption fails to hold, what behavior should result?