rust-lang / rust

Empowering everyone to build reliable and efficient software.
https://www.rust-lang.org
Other
95.39k stars 12.29k forks source link

[Stabilization] Pin APIs #55766

Closed withoutboats closed 5 years ago

withoutboats commented 5 years ago

@rfcbot fcp merge Feature name: pin Stabilization target: 1.32.0 Tracking issue: #49150 Related RFCs: rust-lang/rfcs#2349

This is a proposal to stabilize the pin library feature, making the "pinning" APIs for manipulating pinned memory usable on stable.

(I've tried to write this proposal as a comprehensive "stabilization report.")

Stabilized feature or APIs

[std|core]::pin::Pin

This stabilizes the Pin type in the pin submodule of std/core. Pin is a fundamental, transparent wrapper around a generic type P, which is intended to be a pointer type (for example, Pin<&mut T> and Pin<Box<T>> are both valid, intended constructs). The Pin wrapper modifies the pointer to "pin" the memory it refers to in place, preventing the user from moving objects out of that memory.

The usual way to use the Pin type is to construct a pinned variant of some kind of owning pointer (Box, Rc, etc). The std library owning pointers all provide a pinned constructor which returns this. Then, to manipulate the value inside, all of these pointers provide a way to degrade toward Pin<&T> and Pin<&mut T>. Pinned pointers can deref, giving you back &T, but cannot safely mutably deref: this is only possible using the unsafe get_mut function.

As a result, anyone mutating data through a pin will be required to uphold the invariant that they never move out of that data. This allows other code to safely assume that the data is never moved, allowing it to contain (for example) self references.

The Pin type will have these stabilized APIs:

impl<P> Pin<P> where P: Deref, P::Target: Unpin

impl<P> Pin<P> where P: Deref

impl<P> Pin<P> where P: DerefMut

impl<'a, T: ?Sized> Pin<&'a T>

impl<'a, T: ?Sized> Pin<&'a mut T>

impl<'a, T: ?Sized> Pin<&'a mut T> where T: Unpin

Trait impls

Most of the trait impls on Pin are fairly rote, these two are important to its operation:

std::marker::Unpin

Unpin is a safe auto trait which opts out of the guarantees of pinning. If the target of a pinned pointer implements Unpin, it is safe to mutably dereference to it. Unpin types do not have any guarantees that they will not be moved out of a Pin.

This makes it as ergonomic to deal with a pinned reference to something that does not contain self-references as it would be to deal with a non-pinned reference. The guarantees of Pin only matter for special case types like self-referential structures: those types do not implement Unpin, so they have the restrictions of the Pin type.

Notable implementations of Unpin in std:

These codify the notion that pinnedness is not transitive across pointers. That is, a Pin<&T> only pins the actual memory block represented by T in a place. Users have occassionally been confused by this and expected that a type like Pin<&mut Box<T>> pins the data of T in place, but it only pins the memory the pinned reference actually refers to: in this case, the Box's representation, which a pointer into the heap.

std::marker::Pinned

The Pinned type is a ZST which does not implement Unpin; it allows you to supress the auto-implementation of Unpin on stable, where !Unpin impls would not be stable yet.

Smart pointer constructors

Constructors are added to the std smart pointers to create pinned references:

Notes on pinning & safety

Over the last 9 months the pinning APIs have gone through several iterations as we have investigated their expressive power and also the soundness of their guarantees. I would now say confidently that the pinning APIs stabilized here are sound and close enough to the local maxima in ergonomics and expressiveness; that is, ready for stabilization.

One of the trickier issues of pinning is determining when it is safe to perform a pin projection: that is, to go from a Pin<P<Target = Foo>> to a Pin<P<Target = Bar>>, where Bar is a field of Foo. Fortunately, we have been able to codify a set of rules which can help users determine if such a projection is safe:

  1. It is only safe to pin project if (Foo: Unpin) implies (Bar: Unpin): that is, if it is never the case that Foo (the containing type) is Unpin while Bar (the projected type) is not Unpin.
  2. It is only safe if Bar is never moved during the destruction of Foo, meaning that either Foo has no destructor, or the destructor is carefully checked to make sure that it never moves out of the field being projected to.
  3. It is only safe if Foo (the containing type) is not repr(packed), because this causes fields to be moved around to realign them.

Additionally, the std APIs provide no safe way to pin objects to the stack. This is because there is no way to implement that safely using a function API. However, users can unsafely pin things to the stack by guaranteeing that they never move the object again after creating the pinned reference.

The pin-utils crate on crates.io contains macros to assist with both stack pinning and pin projection. The stack pinning macro safely pins objects to the stack using a trick involving shadowing, whereas a macro for projection exists which is unsafe, but avoids you having to write the projection boilerplate in which you could possibly introduce other incorrect unsafe code.

Implementation changes prior to stabilization

As a general rule, we don't re-export things from multiple places in std unless one is a supermodule of the real definition (e.g. shortening std::collections::hash_map::HashMap to std::collections::HashMap). For this reason, the re-export of std::marker::Unpin from std::pin::Unpin is out of place.

At the same time, other important marker traits like Send and Sync are included in the prelude. So instead of re-exporting Unpin from the pin module, by putting in the prelude we make it unnecessary to import std::marker::Unpin, the same reason it was put into pin.

Currently, a lot of the associated function of Pin do not use method syntax. In theory, this is to avoid conflicting with derefable inner methods. However, this rule has not been applied consistently, and in our experience has mostly just made things more inconvenient. Pinned pointers only implement immutable deref, not mutable deref or deref by value, limiting the ability to deref anyway. Moreover, many of these names are fairly unique (e.g. map_unchecked) and unlikely to conflict.

Instead, we prefer to give the Pin methods their due precedence; users who need to access an interior method always can using UFCS, just as they would be required to to access the Pin methods if we did not use method syntax.

The current ordering is inconsistent with other uses in the standard library.

This impl is not justified by our standard justification for unpin impls: there is no pointer direction between Pin<P> and P. Its usefulness is covered by the impls for pointers themselves.

This futures impl will need to change to add a P: Unpin bound.

Pin should be a transparent wrapper around the pointer inside of it, with the same representation.

Connected features and larger milestones

The pin APIs are important to safely manipulating sections of memory which can be guaranteed not to be moved out. If the objects in that memory do not implement Unpin, their address will never change. This is necessary for creating self-referential generators and asynchronous functions. As a result, the Pin type appears in the standard library future APIs and will soon appear in the APIs for generators as well (#55704).

Stabilizing the Pin type and its APIs is a necessary precursor to stabilizing the Future APIs, which is itself a necessary precursor to stabilizing the async/await syntax and moving the entire futures 0.3 async IO ecosystem onto stable Rust.

cc @cramertj @RalfJung

yasammez commented 5 years ago

To bikeshed a bit more, today at lunch I came up with LeavePin. It carries the same tone as escape without the implied misleading semantics.

vi commented 5 years ago

Are there any interesting interactions between impl specialistion and pins, as is with lifetimes?

The substring "specializ" occurs in tracking issue discussion a bit, but it's not conclusive. Pin RFC or specialisation RFC should explicitly mention this interaction, either as "It's verified to be OK" or "further research is needed to judge it safe".

withoutboats commented 5 years ago

@vi not only is there no soundness interaction, its not possible for there to be a soundness interaction. The pin APIs are strictly defined in the standard library and involve no new language features, a user can define them just as easily in a third party libraries. If a language feature is unsound in the face of this library code existing, it is unsound period, because any user could write this library code today and it will compile fine.

Centril commented 5 years ago

If a language feature is unsound in the face of this library code existing, it is unsound period, because any user could write this library code today and it will compile fine.

Not that it should have any bearing on pin... but I don't think it's nearly as simple as that.

If a library feature, when using unsafe, is making use language constructs whose behavior are as of yet unspecified (e.g. &packed.field as *const _, or making various assumptions about ABI) then if additional language changes invalidate the assumptions of those libraries then I think that it is the libraries which are unsound and not the language changes. On the other hand, if language changes make defined behavior unsound then it's the fault of the language changes. Compiling fine is thus not a sufficient condition for the soundness of a library in the face of unsafe and language changes.

ejmahler commented 5 years ago

+1 to MoveFromPin or similar

If you ask the question "When should I unimplement Unpin for my own type?", the answer is much more clear if you instead ask "When should I unimplement MoveFromPin for my own type?"

Same with "Should I add Unpin as a trait bound here?" vs "should I add MoveFromPin as a trait bound here?"

glandium commented 5 years ago

Pinning is not !Move

Sorry if this was mentioned somewhere, but I only skimmed the vast amount of discussion there has been around Pin here, in the implementation issue, and in the RFC issue.

Will rust ever have !Move? I can certainly see use cases for such a thing (heck, I came looking about Pin because I was looking for a way not to shoot myself in the foot with types that can't be moved). If the answer is yes, how would that interact with Pin? Would the existence of Pin make it harder than it already is to add !Move?

rfcbot commented 5 years ago

The final comment period, with a disposition to merge, as per the review above, is now complete.

tikue commented 5 years ago

There should be an unresolved concern around the naming of Unpin.

jonhoo commented 5 years ago

As @RalfJung pointed out, #55992 also only adds a small amount of the extra documentation asked for in https://github.com/rust-lang/rust/issues/55766#issuecomment-438316891 and elsewhere. Don't know that that's grounds for not merging yet though.

wmanley commented 5 years ago

Why does my drop() method now again take &mut self, instead of a Pin.

Well, drop() is old -- it exists since Rust 1.0 -- so we cannot change it. We'd love to just make it take Pin<&mut Self>, and then Unpin types could get their &mut like they do now, but that's a non-backwards-compatible change.

I was wondering if it would be possible to implement this change in a backward compatible way. AIUI until we add Unpin (and people can specify !Unpin) all types implement Unpin. So we could add a trait:

trait DropPinned {
    fn drop(Pin<&mut> self);
}

and then impl this trait for all Unpin types, which until people can opt out is all types. Something like:

impl<T> PinDrop for T where T:Unpin + Drop {
    fn drop(Pin<&mut T> self) {
        Drop::drop(self.get_mut());
    }
}

Then we'd have the compiler insert calls to DropPinned::drop instead of Drop::drop. Essentially trait DropPinned becomes the lang-item rather than Drop. AFAICS this would be backward compatible if and only if this mechanism was introduced at the same time as Unpin.

cramertj commented 5 years ago

There should be an unresolved concern around the naming of Unpin.

@tikue No libs team member filed a concern with rfcbot before or during the FCP, and I don't believe any of the arguments about Unpin were new or novel to this thread, so typically our process would consider the current naming to be finalized. Obviously if someone has concerns they should speak up, but the point of having team checkboxes followed by FCP is to ensure that the everyone is comfortable stabilizing the API as-proposed.

jonhoo commented 5 years ago

@cramertj I'm a little confused. Several people have spoken up. When I asked for references about where else the arguments about the naming of Unpin had been raised and resolved, I was pointed to https://internals.rust-lang.org/t/naming-pin-anchor-move/6864, which as far as I can see also has people complaining about the naming of Unpin, and no real counter-argument. The original RFC in https://github.com/rust-lang/rfcs/pull/2349 also does not have much rationale as to why proposed alternatives to Unpin are worse. Even in this thread, it seems like the only counter-arguments that really come up are "it's shorter" and "it's technically correct". Are you able to point to concrete discussion where alternative names that are easier to understand (such as MoveFromPin) are discussed and rejected?

tikue commented 5 years ago

I have explained in previous comments why I believe novel perspectives have been brought up in this thread. I've been following the pin API discussions fairly closely since inception and don't remember ever seeing the double negative issue brought up before this thread.

cramertj commented 5 years ago

@tikue I've brought up and seen the double-negative issue brought up multiple times, and the precise naming of Unpin has been raised as an issue many times over and has consistently been resolved in favor of Unpin. As I said before, if someone on the libs team wants to register a (late) objection then I'm fine responding to that, but they all signed off on the stabilization proposal above which clearly does not include the naming of Unpin as an unresolved question: we've discussed the alternatives, and this FCP was the process for deciding that we were prepared to stabilize on the decisions that had been made, including the name Unpin.

jonhoo commented 5 years ago

@cramertj Could you please provide a link to where that discussion has happened? I'm not doubting you, would just like to see the arguments in favor of Unpin, because I do not believe they have been given here. As mentioned, the references I've been given so far do not provide any resolution on the naming of Unpin.

tikue commented 5 years ago

@cramertj +1 to @jonhoo's ask. If there are discussions that the libs team had among themselves that are not registered in official channels, I think the main thrust of those discussions ought to be reiterated here. I think there is even an official rule that RFC decisions can only be made based on publicly-known arguments?

cramertj commented 5 years ago

I think there is even an official rule that RFC decisions can only be made based on publicly-known arguments?

Yup, that's true-- and for the record, I'm not on the libs team and so haven't been present for any libs-team only discussions. Looking through the RFC thread and the Pin tracking issue, there were numerous times where the name of Unpin was brought up. I don't see anyone specifically say the words "double negative", but I certainly remember "!Unpin is a double negative" being brought up before, in addition to the general API rule of naming traits for what you can do with them, rather than what you can't (as I pointed out above, I think Unpin actually follows both these rules, though realizing that requires hearing "Unpin" as a verb rather than hearing it as an adjective "not-pin", which isn't intuitive to folks).

RalfJung commented 5 years ago

@wmanley That does not work, e.g. impl<T> Drop for Vec<T> would break because we do not have Vec<T>: Unpin. Also, proposals along this line have been made before, even in this thread. Please read the discussions before replying. I know that's asking quite a lot, but it is the only way to avoid the same issues being explained again and again.

steveklabnik commented 5 years ago

I think there is even an official rule that RFC decisions can only be made based on publicly-known arguments?

This is informally known as the "no new rationale" rule.

DutchGhost commented 5 years ago

Not sure where to post this, but could someone take a look at https://github.com/rust-lang/rust/issues/56256 ?

Nemo157 commented 5 years ago

Related to #56256, impl<T> From<Box<T>> for Pin<Box<T>> is not listed in the OP as being stabilized, but it will implicitly become stable once Pin does. Are there any other trait implementations that are non-trivial and should be looked at for stabilization? (scanning the docs all the others appear to be trivial delegating implementations for the wrapped pointer to me).

Kimundi commented 5 years ago

We talked about this Issue in the libs team today. The last weeks of discussion have shown that there are still a few things that should get addressed first, especially regarding the naming of Unpin.

Therefore we will not move forward with stabilizing this for now (FCP notwithstanding).

It would be much appreciated if someone could gather up the ideas in this thread and prepare a standalone proposal for improving the naming situation.

cramertj commented 5 years ago

@Kimundi

It would be much appreciated if someone could gather up the ideas in this thread and prepare a standalone proposal for improving the naming situation.

Does this mean that the libs team is unwilling to stabilize the current APIs as-is? I personally don't think that anyone has come up with a better name than the current set of names as-implemented, and so I'm not able to make such a proposal, but I do care a lot about seeing these APIs stabilized, so if someone from the libs team has a name they'd prefer then :shipit:

cramertj commented 5 years ago

Bikeshedded this with a bunch of coworkers and @anp suggested DePin, which I actually like quite a bit, since it removes the "not pin" connotation of Unpin and emphasizes that it's talking about a type which can be de-Pin'd.

aturon commented 5 years ago

@Kimundi can you or someone from the libs team please register an explicit "fcp concern" to take this out of FCP and lay out more clearly what is meant by "a few things taht should get addressed"?

alexcrichton commented 5 years ago

@rfcbot concern naming-of-Unpin

I'm not sure if this works really once FCP is entered, but I'd like to place a formal blocking concern on the naming of the Unpin trait. The Unpin trait looks to be pretty crucial to the API, and the "double negative" (as discussed above) throws me for a spin every time I read it.

There's been a whole bunch of comments about various names, but unfortunately I'm not overly thrilled with any yet. My "favorite" is still along the lines of MoveFromPin or Relocate (my god there are so many comments here I have no idea how to review this).

I'm personally ok with the naming of Pin itself as well as Pinned for a ZST that doesn't implement the Unpin trait.

jonhoo commented 5 years ago

I completely agree with @alexcrichton that the naming of Unpin is the big point of contention here. I don't think there are any technical concerns as far as I can see about the proposed feature itself (though there are a lot of comments, so could have missed something).

I do still think Pinned is a weird name for the ZST, because something that contains a Pinned isn't really pinned.. It just isn't Unpin. PhantomPinned (as it's been renamed to in #55992) has the same issue in that it refers to Pin, when the ZST is really about Unpin.

I also still think the docs need more work given the subtlety of this feature, but that probably doesn't count as a blocker.

Also, @Kimundi, I'm happy to see that the libs team is willing to give this a little more time to settle. It may seem a lot like unnecessary bikeshedding, but I (and others too it seems) think it is pretty important to improve the teachability of this feature :)

tikue commented 5 years ago

Agreed with @jonhoo about Pinned still feeling weird, and PhantomPinned not being any better (it's not Pinned in any way, not even in a phantom way). I think if we find a good name for Unpin, then Pinned will naturally lend itself to being renamed Not{NewNameForUnpin}.

cramertj commented 5 years ago

I really don't think we need to spend any more time discussing PhantomPinned-- this type will almost never appear to end users. PhantomNotUnpin/PhantomNotDePin/PhantomNotMoveFromPin / etc. aren't going to make it any more or less common or make the API more or less obvious to users who are already comfortable enough with the API to have come up with a legitimate use for PhantomPinned.

ghost commented 5 years ago

Just a quick idea: trait Move and ZST Anchor.

Every type is Moveable, unless it contains an Anchor that makes it stick to a Pin. I like how Anchor: !Move intuitively makes a lot of sense.

tikue commented 5 years ago

I'm not suggesting we spend time specifically on PhantomPinned, but I do think it'd be low effort to keep an open mind, because it's possible that whatever is landed on for Unpin will work just as well for PhantomPinned.

cramertj commented 5 years ago

We've covered Move and explained why it's inappropriate numerous times. All types are movable until they are pinned. Similarly, Anchor has previously been suggested but it isn't clear at all from the name that it is used to opt out of Unpining/Moveing.

jonhoo commented 5 years ago

@stjepang I think Move has been discarded a while ago because something being !Unpin does not actually prevent it from being moved. It's only if a type is under a Pin, and it isn't Unpin, that you are "contractually obliged" not to move it.

ghost commented 5 years ago

In the original comment @withoutboats said:

The Pin wrapper modifies the pointer to "pin" the memory it refers to in place

I think it's odd that types implement Unpin because values are not "pinned" - memory is. However, it makes sense to talk about values that are "safe to move". What if we rename Unpin to MoveSafe?

Consider the UnwindSafe trait. It's just a "hinting" marker trait and is safe to implement. If you let a !UnwindSafe value cross a catch_unwind boundary (with AssertUnwindSafe), you'll "break" it by invalidating its invariants.

Similarly, if you have a !Unpin/!MoveSafe value, it can still be moved (of course), but you'll "break" it by invalidating its self-references. The concept seems similar.

The trait Unpin really just means MoveSafe. It seems to me it's not about values that can be moved out of memory behind Pin. Rather, it's about values that won't "break" when you move them.

cramertj commented 5 years ago

MoveSafe has the same problem as Move-- all values any type can be safely moved. It only becomes impossible to move a value after it has been pinned.

ghost commented 5 years ago

MoveSafe has the same problem as Move-- all values any type can be safely moved.

Right, but it's a different meaning of "safe", just like in UnwindSafe. Anyways, I'd be fine with Relocate or anything of that sort.

To summarize, I feel that the trait name should not be DePin, Unpin, or anything with "pin" in its name. To me, that's the main source of confusion. The trait is not really an "escape hatch" from the shackles of Pin - the trait says the value won't be invalidated when moved.

I just see Pin and Unpin as totally separate things. :)

cramertj commented 5 years ago

I feel the exact opposite ;). The trait is only meaningful with respect to Pin, which is the only type we have which meaningfully expresses constraints on the movability of the underlying value. Without Pin, Unpin is entirely meaningless.

DutchGhost commented 5 years ago

I like to think about pinning as putting something on a pinboard. If you remove the pin of an object that is pinned to the board, you can move the object. Removing the pin is Unpinning. I like the name Unpin.

I can also see how !Unpin is a double negation, and can cause confusion. However, I wonder how often you need to write !Unpin.

One other name I could come up with for Unpin is Detach. Back to the pinboard metaphor, you wouldn't Unpin, but Detach the Pin from its object.

RalfJung commented 5 years ago

I think I really like DePin! So far it's my favorite -- it's concise, it's clearly a verb and not an adjective, and !DePin seems pretty clear as well ("cannot be de-pinned").

I think it's odd that types implement Unpin because values are not "pinned" - memory is.

The value is pinned to memory. But the value is crucially important here as well. Pinning memory, for me, is just about making sure that it remains dereferencable or so, but it is not violated by mem::swap. Pinning a value to memory is about not moving that pinned value anywhere else, which is exactly what Pin is about.

josephg commented 5 years ago

I can also see how !Unpin is a double negation, and can cause confusion. However, I wonder how often you need to write !Unpin.

I hear you when you say you don't find the name confusing. I, and many many others in this thread have found ourselves confused by the naming.

I don't have the code at hand, but the first time I tried to use futures I wanted a function to return an impl Future<Output=T>. I can't remember what happened, but I immediately got a gnarly compiler error complaining about T and Unpin. The question I needed an answer for was "Is it safe to constrain T to only be Unpin". And that led me to stare into the abyss for about 2 harrowing hours.

"Oh, ok so if thats what Pin means. So Unpin means .. Box? Why is that a trait?"

"Wait, impl !Unpin? Why is that not impl Pin?"

"Right, Pin and Unpin ... aren't opposites. They're totally different things. Wait, then what does Unpin mean again? Why is it called that?"

"What on earth does !Unpin mean? Not ... the other, not pin thing? Hrrrgh"

Still the only way this makes sense in my head is by replacing 'unpin' with 'relocatable'. "Type is not relocatable in memory" makes complete sense. And yet, even knowing what Pin does, "type is not unpin" leaves me confused.

Renaming Unpin to Relocatable (or Relocate) gets my vote 🗳. But I'd find just about any of the other suggestions better than Unpin.

withoutboats commented 5 years ago

The trait is only meaningful with respect to Pin, which is the only type we have which meaningfully expresses constraints on the movability of the underlying value. Without Pin, Unpin is entirely meaningless.

To put a point on this - the guarantees around pin are entirely around certain behaviors, not types. For example, a generator function which yields () could trivially implement FnOnce by resuming repeatedly. While this type might not implement Unpin - because its yield states could be self-referential, its FnOnce interface (which moves itself) is completely safe because it hasnt yet been pinned when you FnOnce it, which is necessary to bring it into a self-referential state. Unpin is specifically about the kinds of behaviors that are asserted to be safe once the type has been pinned (namely, moving it), not about some intrinsic property of the type.

glaebhoerl commented 5 years ago

Ironically enough I just came here to comment that while the Unpin naming definitely has been debated in the past, the debate over it I remember witnessing was when we chose to replace Move with Unpin, which, I was going to say, is an unambiguous improvement. And often one only realizes later on that, while the current design is a definite improvement over what came before, it still has some room left for yet further improvement. Which is the direction I was coming at this from.

RalfJung commented 5 years ago

Unpin is specifically about the kinds of behaviors that are asserted to be safe once the type has been pinned (namely, moving it), not about some intrinsic property of the type.

The behavior when pinned is an intrinsic property of the type, just like the behavior/invariant when it is shared. I went into this in a lot more detail in this blog post.

withoutboats commented 5 years ago

@RalfJung we're speaking past each other. There's a confusion I see a lot that self-referential types "cannot be moved" - this is not accurate, they have certain states they can enter into during which they cannot be moved, but while they are in other states, it is perfectly safe to move them (and our APIs rely on the ability to move them, for example to apply combinators to them or to move them into a Pin<Box<>>). I'm trying to clarify that its not the case that these types "cannot be moved."

RalfJung commented 5 years ago

Ah, yes, then I agree. A !DePin type is not always pinned, and when it is not, it can be moved like any other type.

alexcrichton commented 5 years ago

@cramertj @withoutboats one thing I haven't quite been able to surise yet, are y'all against renaming Unpin? It doesn't sound like y'all feel you agree it needs to be renamed, but I'm not sure if you're against it.

Centril commented 5 years ago

I personally don't think the main problem here lies with the name Unpin and that "if we could just rename it everything would be intuitive". While renaming may help a little bit (and Relocate / DePin seem nice here...), I think the main complexity comes from the concept of pinning itself; it's certainly not one of the easiest concepts to understand or explain; not even nearly.

Therefore, I think the documentation of the core::pin module needs to be beefed up significantly and a lot more examples need to be included. Good examples would both show canonical use cases as well as uses of the unsafe functions and implementations which are unsound.

cramertj commented 5 years ago

@alexcrichton I'm not against renaming, no. I think Unpin is already fine, but I'd be okay with DePin, which is why I suggested it. RemoveFromPin is the most obviously "correct", but verbose to the point of syntactic salt, so I think I'd oppose that name specifically. I am, however, opposed to putting off stabilization indefinitely until we find a name that everyone agrees is the best-- I think the API has some inherent complexities that won't be made dramatically better or worse because of the name of the Unpin trait. I'd really like to push towards stabilization soon in order to prevent more churn to the code, docs, and discussions around futures_api (and so we can start getting the pieces in place to stabilize futures_api itself). Perhaps we should schedule a dedicated name-settling VC meeting so that everyone who has an opinion can pitch their solution and we can have a more high-bandwidth opportunity to settle this?

liigo commented 5 years ago

My vote is std::pin::Reloc (Relocate)

Darsstar commented 5 years ago

I have two very hypothetical situations (well, really just one, but two different executions) of which I wouldn't mind having explicitly stated wether it is allowed or not.

Unpin indicates that it is trivial to transition from all of T's (where T: Unpin) states while in the pinned type-state (I hope I am correctly remembering that term from one of @RalfJung's blog posts) to the not-pinned type-state. Which is why Pin can hand out &mut T.

So let's assume I want to create a type Woof for which it is also always possible to transition from all of Woof's states while in the pinned type-state to the not-pinned type-state, but it isn't trivial to do so and can therefor not implement Unpin, would it be allowed for Woof to have a function like fn unpin(self: Pin<Box<Woof>>) -> Box<Woof>?

Same for a type Meow for which it is only sometimes possible to transition from pinned to not-pinned and a function like fn unpin(self: Pin<Box<Meow>>) -> Result<Box<Meow>, Pin<Box<Meow>>>.