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

Use Try trait to make Once[Cell | Lock]::get_or_try_init generic over return type #107122

Open
wants to merge 2 commits into
base: master
Choose a base branch
from

Conversation

joboet
Copy link
Contributor

@joboet joboet commented Jan 20, 2023

This came up in the stabilization PR: #105587 (comment)

Using Try allows these methods to accept types like Option in cases where there is no applicable error type.

@rustbot label +T-libs-api +T-libs
r? @scottmcm

@rustbot rustbot added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. T-libs Relevant to the library team, which will review and decide on the PR/issue. labels Jan 20, 2023
@rustbot
Copy link
Collaborator

rustbot commented Jan 20, 2023

Hey! It looks like you've submitted a new PR for the library teams!

If this PR contains changes to any rust-lang/rust public library APIs then please comment with @rustbot label +T-libs-api -T-libs to tag it appropriately. If this PR contains changes to any unstable APIs please edit the PR description to add a link to the relevant API Change Proposal or create one if you haven't already. If you're unsure where your change falls no worries, just leave it as is and the reviewer will take a look and make a decision to forward on if necessary.

Examples of T-libs-api changes:

  • Stabilizing library features
  • Introducing insta-stable changes such as new implementations of existing stable traits on existing stable types
  • Introducing new or changing existing unstable library APIs (excluding permanently unstable features / features without a tracking issue)
  • Changing public documentation in ways that create new stability guarantees
  • Changing observable runtime behavior of library APIs

@rustbot rustbot added the T-libs-api Relevant to the library API team, which will review and decide on the PR/issue. label Jan 20, 2023
@c410-f3r
Copy link
Contributor

With this approach, get_or_try_init won't be stabilized before the stabilization of try_trait_v2.

IFAICT and judging from the development around try_trait_v2, such thing will probably take time (years?).

library/core/src/cell/once.rs Outdated Show resolved Hide resolved
{
let mut res: Result<(), E> = Ok(());
Copy link
Member

Choose a reason for hiding this comment

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

Might make sense to check for other uses of res in the relevant files, as that’s the name I use a lot.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

There is one other case in Clone, but I think it's fine as is. I just don't want to use res here since it could cause confusion as to whether it means "result" or "residual".

@joboet
Copy link
Contributor Author

joboet commented Feb 8, 2023

@scottmcm I'm assuming this looks good to you? Assigning it to someone from libs-api for their approval...

r? libs-api

@rustbot rustbot assigned BurntSushi and unassigned scottmcm Feb 8, 2023
@BurntSushi
Copy link
Member

I'm not sure how I feel about this. The type signature here is really unwieldy. But I suppose that will be a problem for any API that is generic over Try. But do we really need to make this API generic? It's not obvious to me that we do. If Result is the 99% case, then I'm not sure making the API much more difficult to understand is worth doing. And it also means that the API for returning Result is probably not going to get stabilized soon, which is also unfortunate.

@joboet
Copy link
Contributor Author

joboet commented Feb 8, 2023

I'm not sure how I feel about this. The type signature here is really unwieldy. But I suppose that will be a problem for any API that is generic over Try. But do we really need to make this API generic? It's not obvious to me that we do. If Result is the 99% case, then I'm not sure making the API much more difficult to understand is worth doing. And it also means that the API for returning Result is probably not going to get stabilized soon, which is also unfortunate.

I'd say Option is actually more useful here, since it can be used to simply abort the initialization without "giving reasons". Most truly fallible operations (like filesystem accesses) cache their errors and so should use get_or_init. Making the function generic avoids restricting either use.

From a syntax point of view, having to specify the result type explicitly is very unlikely as just using Some(val) or Err(error) already indicates to the compiler that Option/Result is meant. I do agree that the signature looks unwieldy, however.

@BurntSushi
Copy link
Member

I'd say Option is actually more useful here

Is it? I just did a search and I can't find any use cases using Option. Many are using Result with errors though. This is for existing uses of OnceCell (whether from tokio or once_cell):

@BurntSushi
Copy link
Member

Making the function generic avoids restricting either use.

My mind's eye sees it as less "restrictive" and more "less convenient." If you really do want to return an Option<T> but the only API available to use is Result, then you can return a Result<T, ()> and then get an option by calling Result::ok.

@bors
Copy link
Contributor

bors commented Mar 30, 2023

☔ The latest upstream changes (presumably #105587) made this pull request unmergeable. Please resolve the merge conflicts.

@workingjubilee
Copy link
Member

In any case, this seems to need a rebase.
@rustbot 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 Jul 26, 2023
@joboet
Copy link
Contributor Author

joboet commented Jul 26, 2023

@rustbot ready
Rebased.

@rustbot rustbot added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. and removed S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. labels Jul 26, 2023
@bors
Copy link
Contributor

bors commented Jul 31, 2023

☔ The latest upstream changes (presumably #114272) made this pull request unmergeable. Please resolve the merge conflicts.

@jieyouxu
Copy link
Member

cc @joboet from triage: marking this PR as waiting-for-author due to merge conflicts.
@rustbot 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 18, 2024
@joboet
Copy link
Contributor Author

joboet commented Feb 26, 2024

I think this is blocked on a team decision on the proper design of the Try trait. There is an increasing number of functions like this in the library API, and this should IMHO be decided for all of them.

@rustbot label +S-blocked -S-waiting-on-author

@rustbot rustbot added S-blocked Status: Marked as blocked ❌ on something else such as an RFC or other implementation work. and removed S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. labels Feb 26, 2024
@Dylan-DPC Dylan-DPC added S-waiting-on-team Status: Awaiting decision from the relevant subteam (see the T-<team> label). and removed S-blocked Status: Marked as blocked ❌ on something else such as an RFC or other implementation work. labels Sep 23, 2024
@Amanieu
Copy link
Member

Amanieu commented Sep 24, 2024

We discussed this in the libs-api meeting today. Any APIs that could make use of Try should do so, even if that keeps them unstable for now. We've also nominated the Try trait for discussion next week to look into moving it forward.

@rustbot

This comment was marked as outdated.

@joboet
Copy link
Contributor Author

joboet commented Oct 1, 2024

Sorry, made an error while rebasing.
@rustbot ready

@rustbot rustbot added the S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. label Oct 1, 2024
@joboet joboet removed the S-waiting-on-team Status: Awaiting decision from the relevant subteam (see the T-<team> label). label Oct 1, 2024
@BurntSushi
Copy link
Member

BurntSushi commented Oct 1, 2024

Any APIs that could make use of Try should do so, even if that keeps them unstable for now.

I don't think I'm fully on board with this personally. Or at the very least, I'm pretty unhappy with where we've ended up. The difference in type signature complexity is pretty wild, and it isn't totally clear to me that the complexity is buying us much. Compare the status quo:

pub fn get_or_try_init<F, E>(&self, f: F) -> Result<&T, E>
where
        F: FnOnce() -> Result<T, E>,

With Try trait support:

pub fn get_or_try_init<'a, F, R>(&'a self, f: F) -> <R::Residual as Residual<&'a T>>::TryType
    where
        F: FnOnce() -> R,
        R: Try<Output = T, Residual: Residual<&'a T>>,

I find this signature very difficult to read personally. And using this for the basic case of returning a Result<&T, E> seems like an overpowered hammer. The motivation for making this generic was Option, but AFAIK, one can just as easily use Result<&T, ()> and call Result::ok to get an Option without much fuss. I understand that's kind of a hack on the Result API, but I think I'd rather have that than a type signature like the above.

I think we are in a tough spot. I don't really know what to do here:

  • Just keeping the status quo is not ideal because then there isn't a method that supports the full generality of Try for the niche cases where that's required. (Although other than Option, none have been brought up.)
  • Adding two methods (one for Result specifically and one that is generic) also feels bad and also sets an annoying precedent. Not to mention trying to come up with names to distinguish them.
  • Why have the Try trait and then not use it? That also seems bad.

I am very conflicted on what to do here. But I am very unhappy with type signatures that look like this when the 99% use case would be serviced by something more concrete.

@jplatte
Copy link
Contributor

jplatte commented Oct 1, 2024

Why have the Try trait and then not use it? That also seems bad.

To me, the one important purpose of Try is ? overloading. There are other traits for operator overloading that are virtually never used as generic bounds. Personally I'd be quite okay with this being the case for Try too.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. T-libs Relevant to the library team, which will review and decide on the PR/issue. 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.