From what I've gathered reading tutorials, an often repeated statement is Pin prevents an object from being moved. Just ctrl+f "move" at these turorials 1 2 3 4 and in the async book where it says
Pinning makes it possible to guarantee that an object implementing
!Unpin
won't ever be moved.
Okay, so I'm someone who knows nothing about Pin
. I have no background context to work off of so I read that with a pure mind ready to take everything literally. So I go and write
fn move_me(v: Pin<Box<Vec<u8>>>) {}
let mut v = Box::pin(Vec::<u8>::new());
move_me(v);
No error.. I read the Pin
docs and figure out that P
in Pin<P>
must implement !Unpin
or not implement Unpin
. Vec
implements Unpin
. So Box<Vec>
implements Unpin
. Looking at the docs, I can stuff a struct with a PhantomPinned
field to mark it as !Unpin
.
struct NotUnpin { _p: PhantomPinned }
fn move_me(n: Pin<Box<NotUnpin>>) {}
let mut n = Box::pin(NotUnpin{ a: 1, _p: PhantomPinned::default() });
move_me(n);
Again no error. an object implementing !Unpin
won't ever be moved. After looking and looking at example after example I notice all of them are using &mut Pin<...>
.
let mut n = Box::pin(NotUnpin{ a: 1, _p: PhantomPinned::default() });
move_me(&mut n);
Still no error. Well if we're taking an exclusive reference &mut Pin<...>
that means we are trying to mutate it. What the heck lets try
let mut n = Box::pin(NotUnpin{ a: 1, _p: PhantomPinned::default() });
self.a = 1; // cannot assign to data in dereference of `Pin<Box<NotUnpin>>`
Finally! Proof-by-elimination. So the word move is some kind of metaphor for mutation. Or rather, mutation is a metaphor for move? When I assign over old data, I just think I'm copying data from one variable to the other. Move here is such an overloaded term I don't know what is being referred to. Move as in simple copy or move semantics copy-and-destroy or or.. Ambiguity hurts learning, especially if you don't know the disambiguating context that the teacher knows.
The other theme I keep hearing is that Pin
allows you to construct self-referential structs. Again, while this is a metaphorically true statement, it isn't technically true. There are a million safety issues related to self-referential structs not unique to Rust. After pouring through Pin
it seems to me that it instead allows you to safely use (as opposed to construct) already 99% safely defined self-referential data structures. You don't just define a data structure with self-referential pointers, then stick the data structure in a Pin
and walla. Which is what the statement allows you to construct self-referential structs found in many tutorial implies. No, actually literally states.