1

Pin/Unpin was introduced as a prerequisite to adding async/await support to Rust. It allows safely polling a future that potentially has internal refererences to it's own state.

However, wouldn't introducing move-constructors to the language be a simpler solution? This way the future could be moved freely in memory after being polled, all the internal references being fixed by the move-constructor. For example:

async fn foo { /* ... */ }

async fn bar {
    let future = foo();
    poll_fn(|cx| future.poll(cx)).await;
    // Now `future` might have internal references.
    let boxed_future = Box::new(future);
    // The future was moved to the heap, but the move-constructor
    // took care of adjusting the internal references, so we can
    // safely poll the future again.
    boxed_future.await;
}

Surely this approach was contemplated, but ultimately rejected. Why?

rubo
  • 377
  • 1
  • 8
  • I don't understand how moving would help with stuff that can't be moved because that could invalidate references? – cafce25 Dec 09 '22 at 08:24
  • The fact that every object is movable via memcpy is so deeply baked into Rust that your request is similar to asking "Why not just use a different language?". Not quite, but kind of. Also, I don't see how one would implement a move constructor without being forced into `unsafe`; I think the concept of a move constructor is simply incompatible with Rust's borrow checker. – Finomnis Dec 09 '22 at 09:07
  • > "I don't see how one would implement a move constructor without being forced into unsafe" - likewise, one cannot implement a struct using pinning without unsafe. > "I think the concept of a move constructor is simply incompatible with Rust's borrow checker." - could you elaborate on this point? – rubo Dec 09 '22 at 09:19
  • > "I don't understand how moving would help with stuff that can't be moved because that could invalidate references?" - the question is only about self-referrential types, not types that are immovable per se. – rubo Dec 09 '22 at 09:23
  • The problem is that already everything in Rust is trivially movable. So how would you determine if a struct is trivially movable, or if it requires a move constructor? Will every new struct require implementing a move constructor? Will implementing a move constructor override default behaviour? Currently, there is no such thing in Rust as overriding default behaviour. A move behaves identical for every struct. Breaking this would cause major problems for many reasons. – Finomnis Dec 09 '22 at 09:27
  • 1
    A lot of unsafe code, for example, rightfully assumes that one can `memcpy` objects to move them. Adding a move constructor would break all existing unsafe code that uses this assumption. – Finomnis Dec 09 '22 at 09:27
  • *"likewise, one cannot implement a struct using pinning without unsafe."* - Yah, and I think `Pin` was criticized for that already, as being too rushed and unfinished. There are crates like [`pin_project`](https://docs.rs/pin-project) that allow safe abstractions for pinning, though. But in general, yes, pinning is one of the wonkiest language features of Rust, imo. – Finomnis Dec 09 '22 at 09:29
  • *"I think the concept of a move constructor is simply incompatible with Rust's borrow checker." - could you elaborate on this point?"* - I'm not completely sure, but I think it would be really hard to adjust the borrow checker to understand what a move constructor is. And introducing undefined behaviour into Rust is against its main principle. Of course I could be wrong, but I find it hard to imagine how going down that route could ever be done with zero undefined behaviour. – Finomnis Dec 09 '22 at 09:34
  • I think the main problem of your entire question is that you hugely underestimate the impact move constructors would have on the Rust language as a whole. But again, I could be wrong. – Finomnis Dec 09 '22 at 09:36
  • Might be relevant: https://stackoverflow.com/questions/29490670/how-does-rust-provide-move-semantics – Finomnis Dec 09 '22 at 09:39
  • > "I think the main problem of your entire question is that you hugely underestimate the impact move constructors would have on the Rust language as a whole" - don't get me wrong, I have the same gut feeling that introducing move constructors into the language would have dramatic and unpredictable impact on it. I was hoping that somebody would point to a particular problem with it, and it would be easy to say "see, you cannot have move constructors in Rust" or "it does not solve your problem". Your point about unsafe assuming everything is memcpy'able is probably the best answer I see so far. – rubo Dec 09 '22 at 11:09
  • This was definitely discussed, although I don't have time to search for the discussions now. In general, @Finomnis is right: the problem is that too much unsafe code relies on object to be trivially movable. Solutions like `?Move` were proposed, but rejected, I don't exactly remember why. – Chayim Friedman Dec 10 '22 at 20:31

0 Answers0