DerefMove without `&move` refs

Playground

/// 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.

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.

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:

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.

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

Is this any better than the prior art of MoveNew? MoveNew in moveit::new - Rust

1 Like

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.

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).

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