-
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
RFC: Add DerefMove #178
Conversation
👍 |
* 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 |
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>
on Foo
(for some C:Copy
), then *foo
will copy rather than move, right? Therefore, this specification seems circular, e.g. if I also implement DerefMove<Box<()>>
on Foo
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 invoking deref
or deref_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 implemented Deref<int>
, *foo
(where foo: Foo
) would call deref
(because Foo
doesn’t implement DerefMove
). However, if I implemented DerefMove<uint>
on Foo
as well, even a copy like *foo
would call deref_move
, not deref
any more.
In other words, deref_move
is called if it looks like a move or copy. On types that also implement DerefMove
, deref
and deref_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
is Copy
but Foo
probably isn't. It would need to call Deref<int>
on Foo
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:
- If the type implements
DerefMove
but notDeref
orDerefMut
, all dereferences are done usingderef_move
. - If a reference is being taken to a dereference (e.g.
&*ptr
), callderef
orderef_mut
, depending on the mutability of the reference. - If a value is being dereferenced and implements
DerefMove
andDeref
and/orDerefMut
:- If the type is
Copy
, callderef_move
. - Otherwise:
- If the type implements
Deref<T>
whereT: Copy
, call*deref
or*deref_mut
. - Otherwise, call
deref_move
.
- If the type implements
- If the type is
- If a value is being dereferenced and does not implement
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
and DerefMut
, it will choose to use deref
instead of deref_mut
in 3.ii.a and 4.
Thanks for the RFC. I believe the plan is to implement
This has the downside that |
6357402
to
e0acdf4
Compare
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<T>` where `T: Copy`, call `*deref`. |
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.
It's not clear to me what is actually mean here - is this supposed to be *x.deref()
?
I'm concerned about making DerefMove inherit from Deref. Servo needs DerefMove to allow us to create JSRef values on demand that borrow the Root that is being dereferenced. We're hacking around the currently lack of DerefMove by returning a JSRef value that isn't actually valid in all cases; there's no value we could return for Deref that would make sense in a world with DerefMove. |
I guess the best way (from a user perspective) of resolving the issue with // A hypothetical syntax for the above
pub trait DerefMove<T>: for<U> !Deref<U> where T != U {
// ...
} (Pretend the type parameters are associated types, like they should be.) I’m not sure if this would have any other repercussions relating to coherence. |
(meta-comment: could you update the Rendered View link in the top comment?) |
This is an important topic, but not one we are prepared to address now in the runup to 1.0. I hope we can come back to it shortly thereafter. Postponing for now under issue #997. |
Oh, and in case it wasn't clear, thanks very much for the RFC! |
Annotate `CpuFuture` with `#[must_use]`.
Should this issue be reopened now that the original rationale for closing it seems to no longer apply? I think there is quite a bit of interest. |
If you look slightly above your comment, that is tracked in #997. |
Rendered view