Can `Pin` own its referent instead of borrowing mutably?

What I meant for backwards compatibility was that extern types are already in the wild, whereas immovable types aren't. Subordinating immovable types to the design considerations of extern types forces compromises into the design of immovable types which don't need to exist.

Viewing Pin<T> as a wrapper for &mut T for weird T begs the question somewhat, since you're arguing for it to be equivalent to &mut T where T: !DynSized. Also, to the extent that this describes the implementation, you're violating the abstraction barrier. Pin<'a, T> can be viewed in its own right as a unique reference type with lifetime 'a which, for T: !Unpin, can only exist where &mut / move access has been permanently disabled for the referent.

You can’t reborrow it for a shorter lifetime;

https://doc.rust-lang.org/nightly/std/mem/struct.Pin.html#method.borrow

For one thing, safe FFI wrappers ought to be, well, safe, and at least potentially (depending on the design of the foreign library) no less hacky than any other Rust API. If DynSized-related issues are unacceptable for normal Rust code (whether compile-time breakage or runtime panics), they’re also unacceptable for FFI wrappers, and we should just get rid of extern type before it’s stabilized.

In principle, yes, but extern types are a bit of a necessary evil unless/until the soundness issues can be fully addressed. The opportunity exists to have immovable types enter the world entirely absent these issues.

Box-to-Rc comes to mind. I'm pretty sure you'd end up with an uninitialized T at the end of it. I'm not convinced by the argument that immovable types will always be sufficiently abstract that you can't put them in a Box. Maybe you can come up with a scheme that works for generators, but that's far short of a generalized feature, and doesn't address what external library code might (validly?) do.

If DynSized is accepted, and if it moves sufficiently close to closing the soundness holes (for some meaning of "sufficiently close"), then yes, I can see this approach being valid. I don't think an unmitigated zero-size hack should make it into stable/production code.

If the idea is for this proposal to be fully backward-compatible with the existing Pin design, then this doesn't work. Being !DynSized is inseparable from the type, whereas the T in a Pin<T> can have had a fulfilling life as a movable value before getting pinned. Also, unless you want a transition period in which !Unpin types are warned to implement !DynSized with ultimate breakage, Pin<T> needs to be able to maintain its invariants without any changes needed to T. For these reasons, Pin<T> would probably have to be equivalent to something like &mut Pinned<T> where Pinned<T>: !DynSized. (Edit: And this doesn’t address any potential method conflicts, Deref impl conflicts, ...).

The current design of Pin currently has that for the &T case. But yeah, having it just work for &mut T where T: ?Sized is nice, though I'm not sure how common that is compared to &T where T: ?Sized. I'm not entirely convinced about the need for distinguishing whether the referent is movable vs immovable for &T.

1 Like