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

RFC: map_or_default in Option and Result #3148

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
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
82 changes: 82 additions & 0 deletions text/0000-option-result-map-or-default.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
- Feature Name: `option_result_map_or_default`
- Start Date: 2021-07-14
- RFC PR: [rust-lang/rfcs#3148](/~https://github.com/rust-lang/rfcs/pull/3148)
- Rust Issue: [rust-lang/rust#0000](/~https://github.com/rust-lang/rust/issues/0000)

# Summary
[summary]: #summary

`Option` has the methods `unwrap`, `unwrap_or`, `unwrap_or_else` and `unwrap_or_default`. It
similarly has `map`, `map_or`, `map_or_else`, however `map_or_default` is missing. The exact same
problem exists for `Result`. This RFC is a proposal to add this method to `Option` and `Result`.

# Motivation
[motivation]: #motivation

As mentioned before, a user might reasonably expect this method to exist, based on the existence of
other `or_default` methods such as `unwrap_or_default`. Furthermore, this is a very common usecase.
Searching for `map_or_else` in `.rs` files in the official Rust repository it is incredibly common
to see instances like these:

```rust
.map_or_else(String::new, ...)
.map_or_else(SmallVec::new, ...)
.map_or_else(Vec::new, ...)
```

In fact, from a manual count at the time of writing, 25 out of the 57 occurrences of `map_or_else`
in the Rust codebase could have been replaced with an equivalent call to `map_or_default`.

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

The following implementation would get added to `core::option::Option`:

```rust
impl<T> Option<T> {
pub fn map_or_default<U: Default, F: FnOnce(T) -> U>(self, f: F) -> U {
match self {
Some(t) => f(t),
None => Default::default(),
}
}
}
```

The following implementation would get added to `core::result::Result`:

```rust
impl<T, E> Result<T, E> {
pub fn map_or_default<U: Default, F: FnOnce(T) -> U>(self, f: F) -> U {
match self {
Ok(t) => f(t),
Err(e) => Default::default(),
}
}
}
```

# Drawbacks
[drawbacks]: #drawbacks

It adds another method to `Option` and `Result`, which may be considered as cluttered by some.

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

- `.map_or_else(Default::default, ...)` can be written, although it is significantly longer.
- In case `feature(default_free_fn)` stabilizes a user can write `.map_or_else(default, ...)`
after `std::default::default`, which is a bit shorter.

However, neither alternative solves the discrepancy between `unwrap_or_default` existing but
`map_or_default` not existing.

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

We already have `unwrap_or_default`.

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

None.