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 methods for converting from bool to Option<T> #2757

Closed
wants to merge 6 commits into from
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
117 changes: 117 additions & 0 deletions text/0000-bool-to-option.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
- Feature Name: `bool_to_option`
- Start Date: 2019-09-05
- RFC PR: [rust-lang/rfcs#0000](https://github.com/rust-lang/rfcs/pull/0000)
- Rust Issue: [rust-lang/rust#0000](https://github.com/rust-lang/rust/issues/0000)

# Summary
[summary]: #summary

Add methods to `bool` for converting to an `Option<T>`, given a `t: T`, where `true` maps
to `Some(t)` and `false` maps to `None`, abstracting the following common pattern in Rust.

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

# Motivation
[motivation]: #motivation

This is an
[extremely common pattern](https://sourcegraph.com/search?q=repogroup%3Acrates+%2Felse%5Cs*%7B%5Cs*None%5Cs*%7D%2F+count%3A1000)
in Rust code, but is quite verbose, taking several lines to achieve something with only two
important data: the `bool` and the `T`. If we instead collapse the expression on to a single line by
simply removing newlines (i.e. `if some_condition { Some(t) } else { None }`), the legibility of the
code is reduced. In addition, chaining a conversion from a `bool` to an `Option<T>` is inconvenient
in this form and usually requires binding an extra variable to remain readable. Abstracting this
common pattern into a method will make code more readable and require less repetitive typing on the
user's part.

A method for converting from `bool` to `Option<T>` has been requested several times in the past
[[1]](https://github.com/rust-lang/rfcs/pull/2180)
[[2]](https://github.com/rust-lang/rust/issues/50523)
[[3]](https://github.com/rust-lang/rfcs/issues/2606) and shows a significant desire from users.

# Reference-level explanation
[reference-level-explanation]: #reference-level-explanation

Following this proposal, we will add two methods to `bool`:

```rust
impl bool {
fn then_some<T>(self, t: T) -> Option<T> {
if self {
Some(t)
} else {
None
}
}

fn then<T, F: FnOnce() -> T>(self, f: F) -> Option<T> {
if self {
Some(f())
} else {
None
}
}
}
```

The primitive type `bool` currently has no methods, so it will be necessary to add support similarly
to other primitive types that do have methods, like
[`char`](https://doc.rust-lang.org/src/core/char/methods.rs.html#11-1393). This will require the
addition of a new lang item: `#[lang = "bool"]`.

A reference implementation is provided in [#64255](https://github.com/rust-lang/rust/pull/64255).

# Drawbacks
[drawbacks]: #drawbacks

Save the usual drawbacks of adding a new method to the standard library, there are no
drawbacks.

# Rationale and alternatives
[rationale-and-alternatives]: #rationale-and-alternatives

The implementations here are the only reasonable ones.

The following names have been suggested in the past. The choice in this proposal has been made to
avoid possible confusion (e.g. avoiding a name that suggests a conversion from `bool` to
`Option<()>` rather than `Option<T>`), and to be consist with existing naming conventions,
but ultimately comes down to personal preference and indication of
[community consensus](https://github.com/rust-lang/rfcs/pull/2757#issuecomment-544437510) following
the [examples in the rustc codebase](https://github.com/rust-lang/rust/pull/65195).

- [`to_option` and `to_option_with`](https://github.com/rust-lang/rfcs/pull/2757#issuecomment-529228631)
- [`to_opt` or `then_some`](https://github.com/rust-lang/rfcs/issues/2606#issuecomment-476019577)
- [`then` and `then_do`](https://github.com/rust-lang/rfcs/pull/2180#issuecomment-350498489)
- [`some`](https://github.com/rust-lang/rfcs/issues/2606#issue-387773675)
- [`as_some` and `as_some_from`](https://docs.rs/boolinator/2.4.0/boolinator/trait.Boolinator.html)
- [`some_if` and `lazy_if`](https://github.com/rust-lang/rfcs/pull/2180)

This functionality could instead be provided by a crate (e.g.
[boolinator](https://docs.rs/boolinator/2.4.0/boolinator/)), but this functionality is commonly
desired and an obvious candidate for the standard library, where an external crate for such simple
functionality is not convenient.

Choose a reason for hiding this comment

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

Might as well mention if some_condition { t } as an alternative.

Copy link
Member Author

Choose a reason for hiding this comment

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

Inlining a method body is always a possible alternative, so mentioning it specifically here isn't useful.

Copy link
Member

@kennytm kennytm Nov 9, 2019

Choose a reason for hiding this comment

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

@varkor that does not mean inlining the method body, but to make if x { y } evaluates to Some(y) if x is true and None if x is false (basically an even more controversial version of https://internals.rust-lang.org/t/pre-rfc-break-with-value-in-for-while-loops/11208)

Copy link
Member Author

Choose a reason for hiding this comment

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

Ah, I see. Unless there are serious proponents of that approach, I don't think it's worth including, as it seems like an unviable alternative to me.

# Prior art
[prior-art]: #prior-art

- Jane Street's OCaml Core library contains a
[`some_if`](https://ocaml.janestreet.com/ocaml-core/109.55.00/tmp/core_kernel/Option.html#VALsome_if)
method on `Option`.

# Unresolved questions
[unresolved-questions]: #unresolved-questions

None.

# Future possibilities
[future-possibilities]: #future-possibilities

Methods for converting from a `bool` to a `Result<T, E>`, e.g. `to_result` and `to_result_with`,
would be obvious candidates for inclusion into the standard library, which could also be included
as an addendum to this proposal if desire is expressed.