# DerefMove without \`&move\` refs

**URL:** <https://internals.rust-lang.org/t/derefmove-without-move-refs/17575>\
**Category:** language design\
**Created:** [October 16, 2022, 2:03pm UTC](https://internals.rust-lang.org/t/derefmove-without-move-refs/17575 "2022-10-16T14:03:59Z")\
**Posts on this page:** 7\
**Page:** 1

<div class="post-metadata">

**Author:** ![tema2](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/tema2/32/6498_2.png) [@tema2](https://internals.rust-lang.org/u/tema2)\
**Post date:** [October 16, 2022, 2:03pm UTC](https://internals.rust-lang.org/t/derefmove-without-move-refs/17575/1 "2022-10-16T14:03:59Z")

</div>

[Playground](https://play.rust-lang.org/?version=nightly&mode=debug&edition=2021&gist=488676093cd0046f9ffa6dade5120395)

```rust
/// Trait for allowing moving out of custom types
trait DerefMove: DerefMut where Self::Target: Sized {
    /// destroys container; doesn't run `drop` of contained value; called instead of Drop::drop
    unsafe fn drop_empty(&mut self);
    
    /// dereference to a place with a value. Actual moves happen with that place
    fn deref_place(&mut self) -> Place<'_,Self::Target>;
    
    /// should be called each time after a place got from `deref_place()` gets out of scope:
    /// * this includes pointer style move-ins;
    unsafe fn notify(&mut self) {}
}

```

Pro:

- We go for a more complex desugaring =\> we can completely avoid the need for `&move` references;
- The desugaring for more complex cases can be altered, so it's guaranteed to not touch stack.

Con:

- Cannot handle true DST moves: functions that take them as arguments (`dyn FnOnce()`) would need to receive them as a pointers =\> indirection.

Notes:

- The motivation behind `DerefMove::notify` is to allow more complex scenarios than a box;
- Dropping: when `DerefMove::deref_place` gets called it becomes responibility of the caller to dispose a value from gotten place, this includes maintaining drop flags for that place. When holder value gets empty because of move out it doesn't go through plain drop path - it instead goes through `DerefMove::drop_empty`.

---

<div class="post-metadata">

**Author:** ![afetisov](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/afetisov/32/8508_2.png) [@afetisov](https://internals.rust-lang.org/u/afetisov)\
**Post date:** [October 16, 2022, 10:40pm UTC](https://internals.rust-lang.org/t/derefmove-without-move-refs/17575/2 "2022-10-16T22:40:47Z")

</div>

So you're basically proposing to change compiler-tracked destructive moves into a "move leaves an unspecified state", like in C++? I think I'll pass.

`DerefMove` in particular is nowhere near important enough to introduce such hacks into the language.

---

<div class="post-metadata">

**Author:** ![tema2](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/tema2/32/6498_2.png) [@tema2](https://internals.rust-lang.org/u/tema2)\
**Post date:** [October 17, 2022, 5:04pm UTC](https://internals.rust-lang.org/t/derefmove-without-move-refs/17575/3 "2022-10-17T17:04:44Z")

</div>

> [@afetisov](#):
>
> So you're basically proposing to change compiler-tracked destructive moves into a "move leaves an unspecified state"

No, I propose to allow destructive moves on arbitrary types by allowing them to return pointers to their held values, so they can be moved in\out later. A value or it's part is considered to be moved out from the **call** to `deref_place` until return from `notify`;

They are called together on moving in a value or its part.

This way place gottten from value that implements `DerefMove` is considered to be partially initialized when it's content gets moved out, as with `Box`:

```rust
let mut x = Box::new(S {a: 10,b: "a".to_string()});
let b = x.b; // here, x.b is moved out (wow); here `DerefMove::deref_place` has been called
//here x is destroyed through `drop_empty`, right after calling `Drop::drop_in_place(DerefMove::deref_place().ptr as &mut _)`

```

This way, move leaves specified state.

---

<div class="post-metadata">

**Author:** ![beepster](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/beepster/32/7914_2.png) [@beepster](https://internals.rust-lang.org/u/beepster)\
**Post date:** [October 26, 2022, 4:57am UTC](https://internals.rust-lang.org/t/derefmove-without-move-refs/17575/4 "2022-10-26T04:57:34Z")

</div>

Do you have an example of a situation that would require notify?

---

<div class="post-metadata">

**Author:** ![riking](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/riking/32/2818_2.png) [@riking](https://internals.rust-lang.org/u/riking)\
**Post date:** [October 26, 2022, 7:35pm UTC](https://internals.rust-lang.org/t/derefmove-without-move-refs/17575/5 "2022-10-26T19:35:50Z")

</div>

Is this any better than the prior art of MoveNew? [MoveNew in moveit::new - Rust](https://docs.rs/moveit/latest/moveit/new/trait.MoveNew.html)

---

<div class="post-metadata">

**Author:** ![tema2](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/tema2/32/6498_2.png) [@tema2](https://internals.rust-lang.org/u/tema2)\
**Post date:** [October 26, 2022, 10:22pm UTC](https://internals.rust-lang.org/t/derefmove-without-move-refs/17575/6 "2022-10-26T22:22:39Z")

</div>

Example use case for this I imagine is `DOMNodeHandle` that deref's to `DOMElement` type; Or building some kind of reactive containers (that know whether they have got anything changed in them). Interacting with handles to buffers not in main RAM (so that `notify` triggers transfers); Not sure if such an implicitness is justified though.

> [@riking](#):
>
> Is this any better than the prior art of MoveNew? [MoveNew in moveit::new - Rust](https://docs.rs/moveit/latest/moveit/new/trait.MoveNew.html)

This is simpler, I don't want to go for any `&move` references because they can only give us move out functionality (given no linear types).

---

<div class="post-metadata">

**Author:** ![system](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/system/32/14092_2.png) [@system](https://internals.rust-lang.org/u/system)\
**Post date:** [January 24, 2023, 10:22pm UTC](https://internals.rust-lang.org/t/derefmove-without-move-refs/17575/7 "2023-01-24T22:22:45Z")

</div>

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.
