For 1, I think it's hard to make a distinction between swapping an object, vs. swapping/mutating all of its fields such that it becomes equivalent to a different object.

For 3, some objects only need to be pinned under certain circumstances, e.g. futures only need to be pinned after they're polled for the first time, but not before. So it's convenient to separate the pinnability property to allow them to be moved freely beforehand.

I don't quite understand the usecase you have in mind for 4.

> For 1, I think it's hard to make a distinction between swapping an object, vs. swapping/mutating all of its fields such that it becomes equivalent to a different object.

Privacy. If an object has fields I can’t access, but I have an &mut reference, I can indirectly modify them by swapping the object.

More generally, there are a handful of special-seeming things one can do to an object: dropping it, swapping it, forgetting it, and leaking it. Rust does not offer especially strong controls for these except for pinned objects, and even then it feels like the controls are mostly a side effect of pinning.

> For 3, some objects only need to be pinned under certain circumstances, e.g. futures only need to be pinned after they're polled for the first time, but not before.

Is this actually useful in practice? (This is a genuine question, not a rhetorical question. But maybe let’s pretend that Rust had the cool ability to farm out initialization if uninitialized objects described in the OP: allowing access before pinning sounds a bit like allowing references to uninitialized data before initializing it.)

For #4, I’m not sure I have a real use case. Maybe I’ll try contemplating a bit more. Most I think that shared ^ exclusive is a neat concept but that maybe there’s room to extend it a little bit, and there isn’t any fundamental reason that a holder of an &mut reference needs to ensure that no one else can even identify the object while the &mut reference is live.

> Is this actually useful in practice?

It's required to do any intialization, particularly for compound futures (e.g. a "join" or "select" type of combinator), since you need to be able to move the future from where it's created to where it's eventually used/polled. I assume some of those cases could be subsumed by &uninit if that existed yeah.

Passing an &uninit to a combinator seems like it would be strange.

But if you told me that some strongly typed language wanted to have coroutines and futures, that coroutine bodies would not execute at all until first polled, and that it was okay to move the thing you have before polling not the thing you had after polling, and I hadn’t seen Rust, I would maybe suggest:

1. Creating a Future (i.e. logically calling an async function) would return an object that is, conceptually, a NotYetPolledFuture. That object is movable or relocatable or whatever you call it (or it’s movable if and only if the parameters you passed are).

2. Later you exchange that object for a LiveFuture, which cannot be moved.

Rust has two limitations that would make this awkward:

- Rust doesn’t actually have immovable objects per se.

- The exchange is spelled fn exchange(val: Type1) -> Type2, which doesn’t work if Type2 is immovable.

But the &uninit/&own proposal in the OP is actually secretly a complex scheme using lifetimes to somewhat awkwardly do an in-place exchange from an uninitialized type to an initialized and owned type. Maybe that proposal could be extended a little bit to allow type exchanges. (Maybe it already does, sort of? You could pass an &uninit Future and a FutureToken and get out an &own Future, with the caveat that this would force the fields in the token to be moved unless the optimizer did something truly heroic.)