From e33efb4b0366bbaf278f1c69727007ca0ba6db4c Mon Sep 17 00:00:00 2001 From: P1start Date: Wed, 23 Jul 2014 22:59:53 +1200 Subject: [PATCH 1/6] Add DerefMove RFC --- active/0000-deref-move.md | 76 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 76 insertions(+) create mode 100644 active/0000-deref-move.md diff --git a/active/0000-deref-move.md b/active/0000-deref-move.md new file mode 100644 index 00000000000..548a47ef788 --- /dev/null +++ b/active/0000-deref-move.md @@ -0,0 +1,76 @@ +- Start Date: 2014-07-23 +- RFC PR #: (leave this empty) +- Rust Issue #: (leave this empty) + +Summary +======= + +Add a new lang-item-defined trait, `DerefMove`, which allows moves out of custom +pointer types. + +Motivation +========== + +There has been some effort to remove special casing from `Box`—[RFC PR +130](https://github.com/rust-lang/rfcs/pull/130) and RFC PRs +[139](https://github.com/rust-lang/rfcs/pull/139) and +[112](https://github.com/rust-lang/rfcs/pull/112) are examples of this trend. +However, there is still one more problem with `Box` that would have to be fixed +for `Box` to be properly special-case-free (bar the construction syntax and +patterns, which is mostly acceptable because of the plan to support `box` +for other pointer types): `Box` pointers can be moved out of, even though +none of the `Deref*` traits support moves. + +Detailed design +=============== + +Add a new trait, `DerefMove`, with a corresponding lang item, `deref_move`, and +define it in `core::ops`: + +```rust +#[lang="deref_move"] +pub trait DerefMove { + /// The method called to move out of a dereference + fn deref_move(self) -> Result; +} +``` + +The `deref_move` method would be called in any of the following situations: + +* Something is being dereferenced, and the only `Deref*` trait it implements is + `DerefMove`; +* Something is being dereferenced, and while it *does* implement `Deref` and/or + `DerefMut`, it also implements `DerefMove` and a value is being moved out of + the dereference. + +This applies to implicit derefences as well. + +Remove all special treatment of `Box` by the borrow checker. Instead, `Box` +implements `DerefMove` in the standard library roughly as follows: + +```rust +impl DerefMove for Box { + fn deref_move(self) -> T { + let Box(ptr) = self; + std::ptr::read(ptr) + } +} +``` + +Drawbacks +========= + +Adds yet another `Deref*` trait and another lang item, adding complexity to the +language. + +Alternatives +============ + +* Do nothing, and blame `Box`’s special-casing on the fact that it is a lang item + anyway. +* Add a `DerefSet` trait as well, for assignments of the form `*ptr = val`. + +Unresolved questions +==================== + +None. From da71120e18edc6796945fa86a4afb9a5b6392b0a Mon Sep 17 00:00:00 2001 From: P1start Date: Thu, 24 Jul 2014 16:42:51 +1200 Subject: [PATCH 2/6] Clarify dereference rules --- active/0000-deref-move.md | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/active/0000-deref-move.md b/active/0000-deref-move.md index 548a47ef788..2324a0d2179 100644 --- a/active/0000-deref-move.md +++ b/active/0000-deref-move.md @@ -35,13 +35,20 @@ pub trait DerefMove { } ``` -The `deref_move` method would be called in any of the following situations: - -* Something is being dereferenced, and the only `Deref*` trait it implements is - `DerefMove`; -* Something is being dereferenced, and while it *does* implement `Deref` and/or - `DerefMut`, it also implements `DerefMove` and a value is being moved out of - the dereference. +In order to determine which method to use when deferencing with `*`, the +following rules are used: + +1. If the type implements `DerefMove` but not `Deref` or `DerefMut`, all + dereferences are done using `deref_move`. +2. If a reference is being taken to a dereference (e.g. `&*ptr`), call `deref` + or `deref_mut`, depending on the mutability of the reference. +3. If a value is being dereferenced and implements `DerefMove` and `Deref`: + 1. If the type is `Copy`, call `deref_move`. + 2. Otherwise: + 1. If the type implements `Deref` where `T: Copy`, call `*deref`. + 2. Otherwise, call `deref_move`. +4. If a value is being dereferenced and does not implement `DerefMove` but does + implement `Deref`, use `deref`. This applies to implicit derefences as well. From 963a70b182c0d056048902e5825788ea4eeb8c54 Mon Sep 17 00:00:00 2001 From: P1start Date: Thu, 24 Jul 2014 17:00:32 +1200 Subject: [PATCH 3/6] Explain that Box would also implement Deref and DerefMut --- active/0000-deref-move.md | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/active/0000-deref-move.md b/active/0000-deref-move.md index 2324a0d2179..da7da667701 100644 --- a/active/0000-deref-move.md +++ b/active/0000-deref-move.md @@ -52,8 +52,9 @@ following rules are used: This applies to implicit derefences as well. -Remove all special treatment of `Box` by the borrow checker. Instead, `Box` -implements `DerefMove` in the standard library roughly as follows: +Remove all special treatment of `Box` by the borrow checker. Instead, add an +implementation of `DerefMove` for `Box` in the standard library roughly as +follows: ```rust impl DerefMove for Box { @@ -64,6 +65,11 @@ impl DerefMove for Box { } ``` +Add similar implementations of `Deref` and `DerefMut` to the standard library. +Remove all previously built-in dereference functionality for `Box` from the +language, because all dereference functionality is now provided by the standard +library. + Drawbacks ========= From 2bcac4c4db07e2237c9e604de035204687335e92 Mon Sep 17 00:00:00 2001 From: P1start Date: Sat, 16 Aug 2014 07:42:57 +1200 Subject: [PATCH 4/6] fix a few typos; change some wording --- active/0000-deref-move.md | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/active/0000-deref-move.md b/active/0000-deref-move.md index da7da667701..c6a3c831f1b 100644 --- a/active/0000-deref-move.md +++ b/active/0000-deref-move.md @@ -35,7 +35,7 @@ pub trait DerefMove { } ``` -In order to determine which method to use when deferencing with `*`, the +In order to determine which method to use when dereferencing with `*`, the following rules are used: 1. If the type implements `DerefMove` but not `Deref` or `DerefMut`, all @@ -50,9 +50,10 @@ following rules are used: 4. If a value is being dereferenced and does not implement `DerefMove` but does implement `Deref`, use `deref`. -This applies to implicit derefences as well. +This applies to implicit dereferences as well. -Remove all special treatment of `Box` by the borrow checker. Instead, add an +This means that (at least with DST) it is now possible remove all special +treatment of `Box` by the borrow checker. To do this, we would have add an implementation of `DerefMove` for `Box` in the standard library roughly as follows: @@ -65,10 +66,10 @@ impl DerefMove for Box { } ``` -Add similar implementations of `Deref` and `DerefMut` to the standard library. -Remove all previously built-in dereference functionality for `Box` from the -language, because all dereference functionality is now provided by the standard -library. +and also add similar implementations of `Deref` and `DerefMut` to the standard +library. With these changes, it’s now possible to finally remove all previously +built-in dereference functionality for `Box` from the language, because all +dereference functionality is now provided by the standard library. Drawbacks ========= @@ -79,8 +80,8 @@ language. Alternatives ============ -* Do nothing, and blame `Box`’s special-casing on the fact that it is a lang item - anyway. +* Do nothing, and blame `Box`’s special-casing on the fact that it is a lang + item anyway. * Add a `DerefSet` trait as well, for assignments of the form `*ptr = val`. Unresolved questions From 8e2eb3e080d910bafcd0211d26c0988c93400f8a Mon Sep 17 00:00:00 2001 From: P1start Date: Fri, 22 Aug 2014 17:08:35 +1200 Subject: [PATCH 5/6] add more motivation --- active/0000-deref-move.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/active/0000-deref-move.md b/active/0000-deref-move.md index c6a3c831f1b..841192e4d39 100644 --- a/active/0000-deref-move.md +++ b/active/0000-deref-move.md @@ -21,6 +21,12 @@ patterns, which is mostly acceptable because of the plan to support `box` for other pointer types): `Box` pointers can be moved out of, even though none of the `Deref*` traits support moves. +Additionally, this lets custom pointer types like `Cell` be dereferenced. At the +moment, `Cell` doesn’t implement `Deref` or `DerefMut`, because the contents of +`Cell` pointers can’t be referenced for safety reasons. This would allow read +access to the contents of `Cell` pointers (although admittedly not the ability +to modify them). + Detailed design =============== From 758e608bb7ccd16b44c0a68fe0fa2a1dd84ff7f2 Mon Sep 17 00:00:00 2001 From: P1start Date: Sat, 29 Nov 2014 21:42:31 +1300 Subject: [PATCH 6/6] Changes --- {active => text}/0000-deref-move.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) rename {active => text}/0000-deref-move.md (92%) diff --git a/active/0000-deref-move.md b/text/0000-deref-move.md similarity index 92% rename from active/0000-deref-move.md rename to text/0000-deref-move.md index 841192e4d39..4f49cc40bc2 100644 --- a/active/0000-deref-move.md +++ b/text/0000-deref-move.md @@ -51,7 +51,7 @@ following rules are used: 3. If a value is being dereferenced and implements `DerefMove` and `Deref`: 1. If the type is `Copy`, call `deref_move`. 2. Otherwise: - 1. If the type implements `Deref` where `T: Copy`, call `*deref`. + 1. If the type implements `Deref` where `T: Copy`, call `*foo.deref()`. 2. Otherwise, call `deref_move`. 4. If a value is being dereferenced and does not implement `DerefMove` but does implement `Deref`, use `deref`. @@ -89,6 +89,10 @@ Alternatives * Do nothing, and blame `Box`’s special-casing on the fact that it is a lang item anyway. * Add a `DerefSet` trait as well, for assignments of the form `*ptr = val`. +* Add a new `&'a move T` pointer type which can be moved out of, and use it in + the signature for `deref_move` instead. This would be ideal for, for example, + implementing `DerefMove<[T]>` on `Vec`, which would not be possible with the + current version of this RFC. Unresolved questions ====================