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

Tracking issue for bool::then_some #64260

Closed
varkor opened this issue Sep 7, 2019 · 127 comments
Closed

Tracking issue for bool::then_some #64260

varkor opened this issue Sep 7, 2019 · 127 comments
Labels
A-result-option Area: Result and Option combinators B-unstable Blocker: Implemented in the nightly compiler and unstable. C-tracking-issue Category: A tracking issue for an RFC or an unstable feature. disposition-merge This issue / PR is in PFCP or FCP with a disposition to merge it. finished-final-comment-period The final comment period is finished for this PR / Issue. Libs-Tracked Libs issues that are tracked on the team's project board. requires-nightly This issue requires a nightly compiler in some way. T-libs-api Relevant to the library API team, which will review and decide on the PR/issue.

Comments

@varkor
Copy link
Member

varkor commented Sep 7, 2019

Tracking issue for the bool::then_some method, which abstract the following pattern:

if some_condition {
    Some(t)
} else {
    None
}

bool:then has previously been stabilised as part of this feature gate: #79299

RFC: rust-lang/rfcs#2757
Implementation PR: #64255

@varkor varkor added T-libs-api Relevant to the library API team, which will review and decide on the PR/issue. C-tracking-issue Category: A tracking issue for an RFC or an unstable feature. labels Sep 7, 2019
@varkor varkor changed the title Add methods for converting bool to `Option<T> Add methods for converting bool to Option<T> Sep 7, 2019
@Centril Centril added T-lang Relevant to the language team, which will review and decide on the PR/issue. B-unstable Blocker: Implemented in the nightly compiler and unstable. requires-nightly This issue requires a nightly compiler in some way. labels Sep 7, 2019
@Centril Centril changed the title Add methods for converting bool to Option<T> Tracking issue for methods converting bool to Option<T> Sep 8, 2019
@U007D
Copy link

U007D commented Nov 19, 2019

In trying this out, I was puzzled why the eager/lazy argument evaluation versions are then/then_with and not and/and_then, which seems more consistent with established patterns in std?

@varkor
Copy link
Member Author

varkor commented Nov 19, 2019

There's a long discussion in the RFC about the naming. The current names are essentially placeholders.

@jplatte
Copy link
Contributor

jplatte commented Nov 19, 2019

As a datapoint, this feature turns out pretty useful in proc macros, and I do think the current naming reads nicely: https://github.com/ruma/ruma-api/commit/cb00188e0371c544c4b8622d5a32731f2f6c54b3

@varkor
Copy link
Member Author

varkor commented Nov 19, 2019

@jplatte: that would be helpful to share on the RFC!

@c410-f3r
Copy link
Contributor

It's been sometime since the PR implementation.
Is there anything preventing stabilization? If not, I can write a stabilization report for this feature.

@varkor
Copy link
Member Author

varkor commented Dec 21, 2019

@c410-f3r: the names were only decided upon quite recently. It was decided that we would wait a few versions before deciding to stabilise: rust-lang/rfcs#2757 (comment).

@U007D
Copy link

U007D commented Jan 26, 2020

Just came back to give this a test drive in a library I am working on. If we look at common current established patterns in std:

Option:
map<U, F> whereF: FnOnce(T) -> U and
and_then<U, F> whereF: FnOnce(T) -> Option<U>

Result:
map<U, F> whereF: FnOnce(T) -> U and
and_then<U, F> whereF: FnOnce(T) -> Option<U>

And looking at the current implementation of the bool_to_option feature:

bool:
then_some whereF: FnOnce() -> T

The inconsistency is pretty jarring/unexpected, to my mind. Specifically,

  1. for consistency shouldn't bool's F: FnOnce() -> T be called map, and F: FnOnce() -> Option<T> be some then derivative (and_then, then_some, etc.)?
  2. shouldn't bool_to_option also provide both an F: FnOnce() -> T and an F: FnOnce() -> Option<T> implementation?

This is not just hypothetical; I am working on a library with a type that has a two-step fallible constructor. The intent is to be able to write something along the lines of:

...
impl Foo {
    fn new() -> Option<Self> {
        step_1_check().and_then(|| step_2_check().map(|| Self { /* ... */ }))
    }
}

but with the current plan developers would still have to resort to writing a custom combinator or pull in an external crate like boolinator for this simple case.

Thoughts?

@RustyYato
Copy link
Contributor

You can call bool::then followed by Option::flatten to get the same effect. But it does make sense to have a fallible version of bool::then

@jplatte
Copy link
Contributor

jplatte commented Jan 26, 2020

The inconsistency is pretty jarring/unexpected, to my mind.

@U007D: Your comparison is between bool → Option<T> conversion functions and Option<T> → Option<U> (+ Result<T, E> → Result<U, E>) conversion functions. Personally I find that given the input and output types are completely distinct in the new functions when they're not in the ones you're comparing them with is a good reason to consider different names.

@Boscop
Copy link

Boscop commented Jan 29, 2020

@U007D I completely agree. It was already tripping me up many times when using the boolinator crate, which also has inconsistent naming!

IMO these functions should be named consistently with Option/Result.
And not just map and and_then, but it would also make sense to have and, or and or_else.

Or (if that's too much to include into std):
Just have a method on bool that turns a bool into an option fn opt(self) -> Option<()>; (should have a short name), so that we can then use all the above option methods:
b.opt().map(|_| 42), b.opt().and_then(|_| Some(42)), b.opt().and(Some(42)), b.opt().or(Some(42)), b.opt().or_else(|| Some(42)).
Although I'd also prefer to have these as direct methods on bool (or maybe we can let bool be borrowable as &Option<()>, so that we could call Option's methods on a bool?).
But please use consistent naming!

Currently, according to the docs, b.then_some(..) corresponds to b.opt().map(..) whereas b.then(..) corresponds to b.opt().and_then(..), which is not consistent at all.

@djc
Copy link
Contributor

djc commented Mar 8, 2020

How is the libs team feeling about this? Just ran into another case where I'd have liked to use this (on stable).

@djc
Copy link
Contributor

djc commented Apr 2, 2020

@rustbot ping libs

@rustbot
Copy link
Collaborator

rustbot commented Apr 2, 2020

Error: Only Rust team members can ping teams.

Please let @rust-lang/release know if you're having trouble with this bot.

@varkor
Copy link
Member Author

varkor commented Apr 2, 2020

cc @rust-lang/libs regarding naming and stabilisation: #64260 (comment).

@SimonSapin
Copy link
Contributor

@varkor Did you mean to link some other comment? This one does not discuss naming.

I honestly don’t remember the current status of this API.

The current names are essentially placeholders.

Is this still the case or has some consensus been found since?

@varkor
Copy link
Member Author

varkor commented Apr 2, 2020

@SimonSapin: sorry, I should have also linked to the comments above. I think the status is that, modulo outstanding concerns from some users about the naming, these methods are probably suitable for stabilisation.

Is this still the case or has some consensus been found since?

The current names were suggested by @dtolnay. I'm personally happy with the existing names, but there have been some complaints: #64260 (comment), #64260 (comment). However, I think considering how much previous discussion we had on these names, without coming to a clear consensus, I think it's probably worth stabilising with the existing names, so these methods can be used.

Perhaps starting an FCP would be the best way forward with these methods now: if any libs team members decide there are better alternatives, these could be raised during the FCP — otherwise, it would be good to be able to use these on stable.

@Centril Centril removed the T-lang Relevant to the language team, which will review and decide on the PR/issue. label Apr 2, 2020
@SimonSapin
Copy link
Contributor

As a reminder, this issue currently tracks:

impl bool {
    pub fn then_some<T>(self, t: T) -> Option<T> {}
    pub fn then<T, F: FnOnce() -> T>(self, f: F) -> Option<T> {}
}

I can live with this, and more time likely won’t bring new information or ideas at this point.

@rfcbot fcp merge

@rfcbot
Copy link

rfcbot commented Apr 2, 2020

Team member @SimonSapin has proposed to merge this. The next step is review by the rest of the tagged team members:

Concerns:

Once a majority of reviewers approve (and at most 2 approvals are outstanding), this will enter its final comment period. If you spot a major issue that hasn't been raised at any point in this process, please speak up!

See this document for info about what commands tagged team members can give me.

@rfcbot rfcbot added proposed-final-comment-period Proposed to merge/close by relevant subteam, see T-<team> label. Will enter FCP once signed off. disposition-merge This issue / PR is in PFCP or FCP with a disposition to merge it. labels Apr 2, 2020
@withoutboats
Copy link
Contributor

@rfcbot resolve stabilize-only-then

@rfcbot rfcbot added final-comment-period In the final comment period and will be merged soon unless new substantive objections are raised. and removed proposed-final-comment-period Proposed to merge/close by relevant subteam, see T-<team> label. Will enter FCP once signed off. labels Nov 11, 2020
@rfcbot
Copy link

rfcbot commented Nov 11, 2020

🔔 This is now entering its final comment period, as per the review above. 🔔

@rfcbot rfcbot added finished-final-comment-period The final comment period is finished for this PR / Issue. to-announce Announce this issue on triage meeting and removed final-comment-period In the final comment period and will be merged soon unless new substantive objections are raised. labels Nov 21, 2020
@rfcbot
Copy link

rfcbot commented Nov 21, 2020

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

As the automated representative of the governance process, I would like to thank the author for their work and everyone else who contributed.

The RFC will be merged soon.

@varkor
Copy link
Member Author

varkor commented Nov 22, 2020

I've opened a stabilisation PR for then: #79299.

m-ou-se added a commit to m-ou-se/rust that referenced this issue Nov 22, 2020
Stabilise `then`

Stabilises the lazy variant of rust-lang#64260 now that the FCP [has ended](rust-lang#64260 (comment)).

I've kept the original feature gate `bool_to_option` for the strict variant (`then_some`), and created a new insta-stable feature gate `lazy_bool_to_option` for `then`.
m-ou-se added a commit to m-ou-se/rust that referenced this issue Nov 22, 2020
Stabilise `then`

Stabilises the lazy variant of rust-lang#64260 now that the FCP [has ended](rust-lang#64260 (comment)).

I've kept the original feature gate `bool_to_option` for the strict variant (`then_some`), and created a new insta-stable feature gate `lazy_bool_to_option` for `then`.
@spastorino spastorino removed the to-announce Announce this issue on triage meeting label Dec 3, 2020
@jplatte
Copy link
Contributor

jplatte commented Dec 28, 2020

Stabilized; I think this tracking issue can be closed 🙂

@CryZe
Copy link
Contributor

CryZe commented Dec 28, 2020

Only then got stabilized, then_some is still being tracked.

@m-ou-se
Copy link
Member

m-ou-se commented Dec 28, 2020

It might be a good idea to move then_some to a new tracking issue and close this one.

@varkor varkor changed the title Tracking issue for methods converting bool to Option<T> Tracking issue for bool::then_some Dec 28, 2020
@varkor
Copy link
Member Author

varkor commented Dec 28, 2020

I've updated the title and description. I don't think there's any need to create a new issue: that just causes unnecessary churn.

@slerpyyy
Copy link

Does that mean we're still considering stabilizing then_some after all?
I thought we decided that adding then_some was redundant, since then can already do everything then_some can and more.

@varkor
Copy link
Member Author

varkor commented Dec 30, 2020

@slerpyyy: yes, see #64260 (comment). There was a desire to see how useful then_some was in practice as a shorthand. This pattern (taking a value vs taking a closure) is already common throughout the standard library.

@KodrAus
Copy link
Contributor

KodrAus commented Jan 13, 2021

Closing this one in favour of #80967, so that we'll get a chance to issue a fresh FCP if we decide to in the future.

@matklad
Copy link
Member

matklad commented Nov 23, 2021

As an experience report, I've recently found roughly the following code in the wild:

(!is_uppercase)
    .then(|| ())
    .ok_or_else(|| ParseError(ParseErrorKind::Invalid, value.to_string()))

It takes some mental puzzle-solving to figure out whether is_uppercase results in error or not.

Don't think this is actionable in any way, but it's a useful real-world specimen to ponder.

@thomaseizinger
Copy link
Contributor

I think that is a good example that not everything is better with combinators :)

I haven't decipered 100% it but I would write this as:

if !is_uppercase {
    return Err(ParseError(...));
}

Personally, I've been using .then() primarily with .filter_map. I think it is a fantasic fit for that.

@Lucretiel
Copy link
Contributor

Lucretiel commented Nov 23, 2021

Agree, I've seen some similar code in the wild. I think that usually .then() is only appropriate in cases where an Option (or Result, via ok_or_else) is actually in play; .then() followed immediately by *_or_else is probably an antipattern (because you're needlessly round-tripping through an Option). I'd love to see a clippy lint to this effect.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-result-option Area: Result and Option combinators B-unstable Blocker: Implemented in the nightly compiler and unstable. C-tracking-issue Category: A tracking issue for an RFC or an unstable feature. disposition-merge This issue / PR is in PFCP or FCP with a disposition to merge it. finished-final-comment-period The final comment period is finished for this PR / Issue. Libs-Tracked Libs issues that are tracked on the team's project board. requires-nightly This issue requires a nightly compiler in some way. T-libs-api Relevant to the library API team, which will review and decide on the PR/issue.
Projects
None yet
Development

No branches or pull requests