-
Notifications
You must be signed in to change notification settings - Fork 13.6k
Closed
Labels
C-tracking-issueCategory: An issue tracking the progress of sth. like the implementation of an RFCCategory: An issue tracking the progress of sth. like the implementation of an RFCT-libs-apiRelevant to the library API team, which will review and decide on the PR/issue.Relevant to the library API team, which will review and decide on the PR/issue.
Description
Contributor
Issue body actions
Feature gate: #![feature(pin_macro)]
This is a tracking issue for core::pin::pin!
, which allows pinning values to the stack / local scope.
Public API
// core::pin
/// API: `fn pin<T>($value: T) -> Pin<&'local mut T>`
pub macro pin($value:expr $(,)?) {
…
}
Steps / History
- Implementation: Add a stack-
pin!
-ning macro tocore::pin
. #93176Final comment period (FCP)Stabilization PR: Stabilize::{core,std}::pin::pin!
#103800To pick up a draggable item, press the space bar. While dragging, use the arrow keys to move the item. Press space again to drop the item in its new position, or press escape to cancel.
(un)Resolved Questions
Should it be named
pin_mut!
instead, and have apin_ref!
counterpart? (cc @cramertj's Add a stack-pin!
-ning macro tocore::pin
. #93176 (comment))I claim this has been deemed resolved by this conclusion
To pick up a draggable item, press the space bar. While dragging, use the arrow keys to move the item. Press space again to drop the item in its new position, or press escape to cancel.
Metadata
Metadata
Assignees
Labels
C-tracking-issueCategory: An issue tracking the progress of sth. like the implementation of an RFCCategory: An issue tracking the progress of sth. like the implementation of an RFCT-libs-apiRelevant to the library API team, which will review and decide on the PR/issue.Relevant to the library API team, which will review and decide on the PR/issue.
Type
Projects
Milestone
Relationships
Development
Select code repository
Activity
pin!
-ning macro tocore::pin
. #93176[-]Tracking Issue for the `core::pin::pin!`[/-][+]Tracking Issue for `core::pin::pin!`[/+]Auto merge of rust-lang#93176 - danielhenrymantilla:stack-pinning-mac…
pin!()
#96719Rollup merge of rust-lang#96719 - mbartlett21:patch-4, r=Dylan-DPC
jsenkpiel-godaddy commentedon Oct 24, 2022
I feel like this should be called
pin_mut!
and have apin_ref!
counterpart, because you can't feed itT
but only&mut T
/&T
.RalfJung commentedon Oct 25, 2022
Not sure what you mean, you can give it a
T
just fine. You will get aPin<&mut T>
, but that can be easily converted intoPin<&T>
if needed viaas_ref
.danielhenrymantilla commentedon Oct 29, 2022
Ok, after all this time, there have been no issues with
nightly
users of this feature, and the macro seems as good as it is possible to have at the moment.The main unresolved question being about the naming of the macro: should it remain as
pin!
, or should it becomepin_mut!
to pave the way for apin_ref!
counterpart?While
pin_mut!
would be a safe / conservative choice, I think it would be overkill here.To illustrate why, let's start by drawing some parallels with
Box
or other ownership-based APIs.This is a legitimate think to do, since
pin!
ning is the stack/local counterpart ofBox::pin
ning, i.e., its key aspect is ownership-based, not borrowing-based: contrary to the usual getter design of.as_{ref,mut}
,.deref{,_mut}
,ptr::addr_of{_mut}!
,pin!
consumes ownership of its input!And in the same fashion that we have
Box::leak()
consuming ownership of the input, and returning a borrow in output, a borrow which happens to be an exclusive one,pin!
's design is quite similar.And we don't have have
Box::leak_mut()
+Box::leak_ref()
, we just just haveBox::leak()
. Users wanting a shared reference after leaking just have to&*
(the idea being that such function returns&mut
because it's maximally capable, a shared reference being a strictly less powerful API):pin!
uses subtle lifetime extension1, which doesn't allow for methods to be directly called on thepin!
ned thing as it is being assigned to a local. This makes the two lines in the example be required for proper usage, which isn't the case forBox
).On the contrary, if we went with
pin_mut!
, we'd then have a symmetricpin_ref!
/pin_mut!
situation, which I actually find not that useful:As this comment from @Darksonn —the maintainer of a very popular future-based ecosystem— says, the need for
Pin<&_>
s doesn't really occur in practice. While some very specific APIs could end up relying on it, the truth is that it will at most result in an undermining minority, compared to the usage ofPin<&mut>
.As an illustrating example, the very pervasive
#[pin_project]
macro (of the eponymous crate) imbues the annotated type with a.project()
method, which is&mut
-based._mut
suffix;project_ref()
counterpart.On grep.app,
.project()
yields 1539 occurrences2, whereas.project_ref()
yields 15 (with around 5 forpin_project
's "let's keep it general" API itself).That's a difference of two orders of magnitude.
That is, there is little motivation in having a symmetric convenience API for a situation which is hugely asymmetric.
Worse, keeping the symmetry will actually end up being confusing, much like having
Box::leak_mut()
vs.Box::leak_ref()
could have been: since the ref variant could be implemented in terms of themut
one, users could legitimately wonder if there was some other difference they might have missed: it would be a case of accidental complexity, as I view it.pin_mut!
andpin_ref!
could be confusing for Alan, should they decide to try to writeblock_on
,select!
, or something like that without resorting toBox::pin
.Conclusion
pin_mut!
does not seem to pull its weight compared topin!
; we should go with the latter, and ensure a "pit of success" for people such as Alan to use the right tool from the start 🙂, and avoid some bits of accidental complexity.pin_ref!
really be deemed useful, we could always imitate the.project()
/.project_ref()
design of#[pin_project]
:pin!
andpin_ref!
. This would offer the tiny extra flexibility of not requiring two statements for thePin<&_>
case, while still heavily favoring the&mut
case, as it should be).Footnotes
[EDIT] as @tmandry points out, this doesn't even have to remain being an issue in the long term, as finding a way to solve RFC 66 (Better temporary lifetimes (tracking issue for RFC 66) #15023) could help fix this 🤞 ↩
Granted,
.project()
is a potentially more frequent name for other APIs, but from randomly skimming the grep.app page results, I was seeing elements indicative of work onFuture
s orPin
ning. ↩danielhenrymantilla commentedon Oct 29, 2022
That's why I'd vote for:
pin!
(nopin_mut!
), and should people agree with this, it means it's time for:tmandry commentedon Oct 29, 2022
This all sounds good to me. I'm excited to see this move forward, thank you for pushing on it!
Either way is fine but personally I'd make a PR, less chance of getting lost :)
tmandry commentedon Oct 29, 2022
It's worth stating that this is a deficiency of Rust's lifetime extension rules (a deficiency that the definition of
pin!
itself works around by being in std), and would be fixed when RFC 66 is implemented (#15023).15 remaining items