-
Notifications
You must be signed in to change notification settings - Fork 1.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
RFC: Add DerefMove #178
Closed
Closed
RFC: Add DerefMove #178
Changes from 1 commit
Commits
Show all changes
6 commits
Select commit
Hold shift + click to select a range
e33efb4
Add DerefMove RFC
ftxqxd da71120
Clarify dereference rules
ftxqxd 963a70b
Explain that Box would also implement Deref and DerefMut
ftxqxd 2bcac4c
fix a few typos; change some wording
ftxqxd 8e2eb3e
add more motivation
ftxqxd 758e608
Changes
ftxqxd File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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<Result> { | ||
/// 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<T> DerefMove<T> for Box<T> { | ||
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. |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I feel like I am missing something in this second bullet: Whether we choose to move or copy a value is based on the static type of that value's expression. If I implement
Deref<C>
onFoo
(for someC:Copy
), then*foo
will copy rather than move, right? Therefore, this specification seems circular, e.g. if I also implementDerefMove<Box<()>>
onFoo
as well, then I need to know the type of an expression like*foo
to know whether its return value is being copied or being moved, but in order to know what the type of*foo
is, I need to know whether I am supposed to be invokingderef
orderef_move
.But perhaps I have misunderstood your intention, and there is some other property that you are trying to describe here that is unrelated to the type-based move/copy distinction. And if that is the case, perhaps there is another phrasing that would be clearer here. (I'm just guessing now, but would "if the dereference is in an rvalue context" work?)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When I mention a ‘move’ in the RFC, I generally mean a ‘move or copy’. So
deref_move
is called (if is implemented) whenever a value is moved or copied out of a dereference. This means that if I had a struct,Foo
, that implementedDeref<int>
,*foo
(wherefoo: Foo
) would callderef
(becauseFoo
doesn’t implementDerefMove
). However, if I implementedDerefMove<uint>
onFoo
as well, even a copy like*foo
would callderef_move
, notderef
any more.In other words,
deref_move
is called if it looks like a move or copy. On types that also implementDerefMove
,deref
andderef_mut
are only called when an expression along the lines of&*p
or&mut *p
is encountered.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That won't work.
uint
isCopy
butFoo
probably isn't. It would need to callDeref<int>
onFoo
and copy out of the resulting&int
instead.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That’s a good point. Maybe the rules could be revised to this:
DerefMove
but notDeref
orDerefMut
, all dereferences are done usingderef_move
.&*ptr
), callderef
orderef_mut
, depending on the mutability of the reference.DerefMove
andDeref
and/orDerefMut
:Copy
, callderef_move
.Deref<T>
whereT: Copy
, call*deref
or*deref_mut
.deref_move
.DerefMove
but does implementDeref
and/orDerefMut
, usederef
orderef_mut
.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That seems reasonable to me. Presumably if the type implements both
Deref
andDerefMut
, it will choose to usederef
instead ofderef_mut
in 3.ii.a and 4.