Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Arc::into_inner for safely discarding Arcs without calling the destructor on the inner type. #79665

Closed
wants to merge 15 commits into from

Conversation

steffahn
Copy link
Member

@steffahn steffahn commented Dec 3, 2020

Re-opening #75911 after it was closed due to inactivity (sorry for having been so inactive)

  • New commits since since previous PR are starting from 5d81f76:
  • In particular
  • I’m planning to also implement an Rc::into_inner version for Rc, accordingly. Last previous comment on that topic. Probably being added to this PR very soon.
  • For now, the only remaining things I’m not 100% sure about yet are:
    • Are we are keeping the name be into_inner for now or are there people preferring something different?
    • What is the correct way to write documentation in the standard library? I used to have a section in try_unwrap documentation referring to into_inner. I commented that paragraph out for now with a FIXME to make sure it gets re-introduced once into_inner is stabilized; otherwise, it would be confusing if we had a stable function recommended using an unstable one, right? On the other hand the fact that into_inner is not stable doesn’t help the fact that using try_unwrap can introduce bugs... (relevant commit: 00d50fe)
    • How do tracking issues work? When are they created, what’s the timeline? I would guess, perhaps, maybe(?), right before merging this PR would be a good time because then we could still include the issue in the #[unstable(..)] attribute. And perhaps also create a page in the Unstable Book? Or is that supposed to be in a seperate PR?

cc @danielhenrymantilla @Diggsey


This section comes from the previous PR, #75911:


There was previously some discussion on IRLO.

Motivation

The functionality provided by this new “method” on Arc was previously not archievable with the Arc API. The function into_inner is related to (and hence similarly named similar to) try_unwrap. The expression Arc::into_inner(x) is almost the same as Arc::try_unwrap(x).ok(), however the latter includes two steps, the try_unwrap call and dropping the Arc, whereas into_inner accesses the Arc atomically. Since this is an issue in multi-threaded settings only, a similar function on Rc is not strictly necessary but could be wanted nontheless for ergonomic and API-similarity reasons. (This PR currently only offers the function on Arc, but I could add one for Rc if wanted.) In the IRLO discussion, I also mentioned two more functions that could possibly extend this API.

The function Arc::into_inner(this: Arc<T>) -> Option<T> offers a way to “drop” an Arc without calling the destructor on the contained type. When the Arc provided was the last strong pointer to its target, the target value is returned. Being able to do this is valueable around linear(-ish) types that should not or cannot just be dropped ordinarity, but require extra arguments, or operations that can fail or are async to properly get rid of.

Rendered Documentation

Screenshot_20201203_190752

@rust-highfive
Copy link
Collaborator

Thanks for the pull request, and welcome! The Rust team is excited to review your changes, and you should hear from @joshtriplett (or someone else) soon.

If any changes to this PR are deemed necessary, please add them as extra commits. This ensures that the reviewer can see what has changed since they last reviewed the code. Due to the way GitHub handles out-of-date commits, this should also make it reasonably obvious what issues have or haven't been addressed. Large or tricky changes may require several passes of review and changes.

Please see the contribution instructions for more information.

@rust-highfive rust-highfive added the S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. label Dec 3, 2020
@jyn514 jyn514 added the T-libs-api Relevant to the library API team, which will review and decide on the PR/issue. label Dec 3, 2020
@steffahn

This comment has been minimized.

@rustbot rustbot added the C-enhancement Category: An issue proposing an enhancement or a PR with one. label Dec 3, 2020
Copy link
Contributor

@danielhenrymantilla danielhenrymantilla left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like how this is looking! 👌

library/alloc/src/sync.rs Outdated Show resolved Hide resolved
/// ```
///
/// A more practical example demonstrating the need for `Arc::into_inner`:
/// ```
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
/// ```
/// ```no_run

In case a 100_000 iteration loop within a (doc-)test is not deemed desirable.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

At least on my machine this doc-test does not run particularly slowly. There seem to be lots of other doc tests that take much longer than this one. The 100_000 iterations are necessary to ensure stack overflows are even possible on enough platforms.

/// It is strongly recommended to use [`Arc::into_inner`] instead if you don't
/// want to keep the `Arc` in the [`Err`] case.
/// Immediately dropping the [`Err`] payload, like in the expression
/// `Arc::try_unwrap(this).ok()`, can still cause the strong count to
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Talking for the future here, but if/when this feature gets stabilized, it will be nice to have a (clippy?) lint for this 🙂

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't know if this has been done before, but adding a FIXME comment about opening an issue for it on clippy would ensure this is not forgotten when this becomes stable.

Co-authored-by: Daniel Henry-Mantilla <daniel.henry.mantilla@gmail.com>
@poliorcetics
Copy link
Contributor

It looks very very nice, thanks for sticking with this !

If you want to work on Rc::into_inner too, I suggest adding a checklist in the original comment and marking the PR as WIP: or draft so that a reviewer won't approve it before it's ready. 😄

@coolreader18
Copy link
Contributor

Would it make more sense for the signature to be fn into_inner(Self) -> Result<T, Self>, in order to be able to still use the arc if it's not at refcount==1?

@steffahn
Copy link
Member Author

steffahn commented Dec 4, 2020

Would it make more sense for the signature to be fn into_inner(Self) -> Result<T, Self>, in order to be able to still use the arc if it's not at refcount==1?

@coolreader18 no, that’s Arc::try_unwrap. The main point of this PR is that Arc::try_unwrap can be problematic in case you don’t want to be able to still use the arc. Hence the new, additional function. I assume you did read the image with the documentation?

I could take this as a hint that the docs might need improvement. On the other hand, in practice this could not be that confusing since the docs of try_unwrap are going to be right above into_inner:

Screenshot_20201204_025629

@coolreader18
Copy link
Contributor

coolreader18 commented Dec 4, 2020

Ah, whooooopssss, sorry... I was thinking for some reason that nothing like this existed already, but I think I was thinking of a Arc<T> -> Box<T> conversion function (which wouldn't make too much sense anyway).

@camelid camelid added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Jan 15, 2021
@JohnCSimon
Copy link
Member

Ping from triage - @steffahn
apparently this still needs more work
@rustbot label: -S-waiting-on-review +S-waiting-on-author

@rustbot rustbot added S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Feb 7, 2021
@JohnCSimon JohnCSimon added the S-inactive Status: Inactive and waiting on the author. This is often applied to closed PRs. label Mar 1, 2021
@JohnCSimon
Copy link
Member

JohnCSimon commented Mar 1, 2021

@steffahn - Thanks for your contribution but I'm closing this is inactive. If you want to continue feel free to reopen.

@JohnCSimon JohnCSimon closed this Mar 1, 2021
@kvark
Copy link
Contributor

kvark commented Aug 12, 2022

Very unfortunate to see this being closed. What are the steps missing, exactly? Could someone involved in a discussion make a list of things that need to be addressed for this to proceed? I'm sure somebody (if not me) will pick this up. This functionality is very much needed and missing currently. cc @steffahn

@steffahn
Copy link
Member Author

@kvark Thanks for commenting. Reviving this PR was still somewhere deep on my (over-procrastinated) mental TODO list of things I’ll eventually need to get around to. AFAIR, there’s not too much effort necessary to bring this to completion, I’ll have to review the review comments so far, but I don’t remember there being any major problems. Also, this PR is merely about introducing the API behind a feature gate, not stabilizing it.

Thanks for confirming that this functionality is “much needed”; for me personally it was only a technically missing portion of API, but I didn’t have practical need for it personally.

I have also gained more contribution experience in the meantime anyways… let’s see, perhaps I can get this PR back on track fairly quickly… e.g. this weekend, or next week.

@kvark
Copy link
Contributor

kvark commented Aug 12, 2022

I see, thanks for the info! I suppose I can't rely on this right now even if it's merged, given than it's behind a feature gate, so I'll search for a workaround.
To expand on the practical use-case, I'm working on a task scheduler - https://github.com/kvark/choir
The neatest part of it is the implementation detail that the current state of a task is expressed in the type system:

  • if it's Arc<Task> then there are still dependencies not finished
  • once it's Task (extracted currently with Arc::try_unwrap), it can run

I find this very clean and elegant for not relying on any unsafe functionality. But it will only work if I can do "unwrap or drop" atomically, which is what your PR (fortunately) already does. If you have ideas on the minimal workaround, please share them somewhere (matrix, email, etc, not sure if this PR is really appropriate).

@steffahn
Copy link
Member Author

steffahn commented Aug 12, 2022

It it gets merged, stabilization can be the next step and needs not take extraordinarily long though (of course if you need a solution right now or quickly, that’s still not enough). Regarding workarounds, you could

  • use a custom Arc implementation (e.g. by copying the necessary parts from the standard library) that has this functionality added
  • use some custom, less general, solution using atomics (I haven’t though about the details)
  • use a destructor that returns a value somehow, e.g. via a thread-local. That’s some overhead, but possibly it’s low enough (after all, e.g. with Futures and executors, there’s a lot of implicit context being passed in thread-locals, too). Here’s an example: https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=8acc3450726f68a75b3efc04477630c1

@kvark
Copy link
Contributor

kvark commented Aug 14, 2022

I went the route of implementing my own linear Arc and bumped into a (blocker) problem that constructing Arc<T>::new() for unsized T requires the coercion magic in the compiler. I.e. this can't be a matter of just copying parts of the standard library implementation into userspace, unfortunately.
I admit this is a bit of a different issue, but the point is - Arc in std should either have less magic, or be useful enough that people wouldn't need to re-implement it.

@CAD97
Copy link
Contributor

CAD97 commented Aug 14, 2022

Arc isn't magic. The coercion Arc has is automatically afforded to any struct S<T: ?Sized>(ptr::NonNull<SInner<T>>);. triomphe::Arc is an example out-of-std Arc.

@kvark
Copy link
Contributor

kvark commented Aug 14, 2022

@CAD97 this crate relies on a re-implementation of the coercion mechanism - https://crates.io/crates/unsize
So, yes, possible in principle, but unfortunately deeper than just Arc itself.

@kvark
Copy link
Contributor

kvark commented Aug 14, 2022

@steffahn one thing that I believe this PR is missing is a function similar to into_inner but for unsized types. It could return a bool (since it can't return the Option<T>).

@CAD97
Copy link
Contributor

CAD97 commented Aug 14, 2022

Triomphe only uses the unsize crate for thin arcs, IIRC. But yes, I'm very aware of the exact capabilities and limitations of the current unsizing mechanism.

@steffahn
Copy link
Member Author

The code still rebases without problems.

As far as I can tell there aren't actually any blockers to merging this as-is; if I don't implement it now, adding Rc::into_inner can happen later. (The implementation is trivial anyways, it's mostly about finding the right documentation.)

I opened #106854, let's get some progress here, finally.

steffahn added a commit to steffahn/rust that referenced this pull request Jan 21, 2023
…structor on the inner type.

Mainly rebased and squashed from PR rust-lang#79665,
furthermore includes minor changes in comments.
Dylan-DPC added a commit to Dylan-DPC/rust that referenced this pull request Jan 23, 2023
…r=Mark-Simulacrum

Add `Arc::into_inner` for safely discarding `Arc`s without calling the destructor on the inner type.

ACP: rust-lang/libs-team#162

Reviving rust-lang#79665.

I want to get this merged this time; this does not contain changes (apart from very minor changes in comments/docs).

See rust-lang#79665 for further description of the PR. The only “unresolved” points that led to that PR being closed, AFAICT, were

* The desire to also implement a `Rc::into_inner` function
  * however, this can very well also happen as a subsequent PR
* Possible need for further discussion on the naming “`into_inner`” (?)
  * `into_inner` seems fine to me; also, this PR introduces unstable API, and names can be changed later, too
* ~~I don't know if a tracking issue for the feature flag is supposed to be opened before or after this PR gets merged (if *before*, then I can add the issue number to the `#[unstable…]` attribute)~~ There is a [tracking issue](rust-lang#106894) now.

I say “unresolved” in quotation marks because from my point of view, if reviewers agree, the PR can be merged immediately and as-is :-)
thomcc pushed a commit to tcdi/postgrestd that referenced this pull request May 31, 2023
…structor on the inner type.

Mainly rebased and squashed from PR rust-lang/rust#79665,
furthermore includes minor changes in comments.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
C-enhancement Category: An issue proposing an enhancement or a PR with one. S-inactive Status: Inactive and waiting on the author. This is often applied to closed PRs. S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. T-libs-api Relevant to the library API team, which will review and decide on the PR/issue.
Projects
None yet
Development

Successfully merging this pull request may close these issues.