# Replacing combinator functions with language features
This document shows all the `Option` and `Result` combinators that could
potentially be replaced by language features. Each code block shows the
description and signature of a combinator function, followed by one or more
Rust expressions showing how to replace it using `is` or `try`.
Some of these combinators are still potentially useful in other contexts, as
well as in combination with other things that don't have equivalents; an
example replacement for a given combinator does not mean I'm advocating
removing the combinator or suggesting that every use of the combinator can
always be replaced.
## `Option`
```rust
/// Returns `true` if the option is a [`Some`] value.
pub const fn is_some(&self) -> bool;
if opt is Some(_) {}
```
```rust
/// Returns `true` if the option is a [`Some`] and the value inside of it matches a predicate.
pub fn is_some_and(&self, f: impl FnOnce(&T) -> bool) -> bool;
if opt is Some(x) && expr(x) {}
// Handles both by-ref and by-value
if opt is Some(ref x) && expr(x) {}
if &opt is Some(x) && expr(x) {}
```
```rust
/// Returns `true` if the option is a [`None`] value.
pub const fn is_none(&self) -> bool;
if opt is None {}
```
```rust
/// Converts from `&Option<T>` to `Option<&T>`.
pub const fn as_ref(&self) -> Option<&T>;
if opt is Some(ref x) {}
if &opt is Some(x) {}
// If you already have a reference
if opt is Some(x) {}
```
```rust
/// Converts from `&mut Option<T>` to `Option<&mut T>`.
pub const fn as_mut(&mut self) -> Option<&mut T>;
if opt is Some(ref mut x) {}
```
```rust
/// Maps an `Option<T>` to `Option<U>` by applying a function to a contained value.
pub const fn map<U, F>(self, f: F) -> Option<U>;
try { f(x?) }
```
```rust
/// Calls the provided closure with a reference to the contained value (if [`Some`]).
pub const fn inspect<F>(self, f: F) -> Self;
// If the return value doesn't matter:
try { f(x?); }
```
```rust
/// Zips `self` and another `Option` with function `f`.
pub const fn zip_with<U, F, R>(self, other: Option<U>, f: F) -> Option<R>;
try { f(opt_a?, opt_b?) }
```
```rust
/// Returns [`None`] if the option is [`None`], otherwise returns `optb`.
pub const fn and<U>(self, optb: Option<U>) -> Option<U>;
try { opt_a?; opt_b? }
```
```rust
/// Returns [`None`] if the option is [`None`], otherwise calls `f` with the
pub const fn and_then<U, F>(self, f: F) -> Option<U>;
try { f(opt_a?)? }
```
```rust
/// Returns `true` if the option is a [`Some`] value containing the given value.
pub const fn contains<U>(&self, x: &U) -> bool;
if opt is Some(v) && v == x {}
```
```rust
/// Zips `self` with another `Option`.
pub const fn zip<U>(self, other: Option<U>) -> Option<(T, U)>;
try { (opt_a?, opt_b?) }
```
```rust
/// Zips `self` and another `Option` with function `f`.
pub const fn zip_with<U, F, R>(self, other: Option<U>, f: F) -> Option<R>;
try { f(opt_a?, opt_b?) }
```
```rust
/// Maps an `Option<&T>` to an `Option<T>` by copying the contents of the
pub const fn copied(self) -> Option<T>;
opt is Some(&v)
try { *opt? }
```
```rust
/// Maps an `Option<&T>` to an `Option<T>` by cloning the contents of the
pub const fn cloned(self) -> Option<T>;
try { opt?.clone() }
```
```rust
/// Converts from `Option<Option<T>>` to `Option<T>`.
pub const fn flatten(self) -> Option<T>;
try { opt?? }
```
## `Result`
```rust
/// Returns `true` if the result is [`Ok`].
pub const fn is_ok(&self) -> bool;
if x is Ok(_) {}
```
```rust
/// Returns `true` if the result is [`Ok`] and the value inside of it matches a predicate.
pub fn is_ok_and(&self, f: impl FnOnce(&T) -> bool) -> bool;
if x is Ok(v) && expr(v) {}
```
```rust
/// Returns `true` if the result is [`Err`].
pub const fn is_err(&self) -> bool;
if x is Err(_) {}
```
```rust
/// Returns `true` if the result is [`Err`] and the value inside of it matches a predicate.
pub fn is_err_and(&self, f: impl FnOnce(&E) -> bool) -> bool;
if x is Err(e) && expr(e) {}
```
The general case of `as_ref` and `as_mut` isn't replaceable, but any usage that
only needs one variant or the other may be able to use `is`.
```rust
/// Maps a `Result<T, E>` to `Result<U, E>` by applying a function to a
pub fn map<U, F: FnOnce(T) -> U>(self, op: F) -> Result<U, E>;
try { f(x?) }
```
```rust
/// Calls the provided closure with a reference to the contained value (if [`Ok`]).
pub fn inspect<F: FnOnce(&T)>(self, f: F) -> Self;
// If the return value doesn't matter:
try { f(x?); }
```
```rust
/// Returns `res` if the result is [`Ok`], otherwise returns the [`Err`] value of `self`.
pub const fn and<U>(self, res: Result<U, E>) -> Result<U, E>;
try { x?; y? }
```
```rust
/// Calls `op` if the result is [`Ok`], otherwise returns the [`Err`] value of `self`.
pub fn and_then<U, F: FnOnce(T) -> Result<U, E>>(self, op: F) -> Result<U, E>;
try { f(x?)? }
```
```rust
/// Returns `true` if the result is an [`Ok`] value containing the given value.
pub fn contains<U>(&self, x: &U) -> bool;
if res is Ok(v) && v == x
```
```rust
/// Maps a `Result<&T, E>` to a `Result<T, E>` by copying the contents of the
pub fn copied(self) -> Result<T, E>;
try { *x? }
```
```rust
/// Maps a `Result<&T, E>` to a `Result<T, E>` by cloning the contents of the
pub fn cloned(self) -> Result<T, E>;
try { x?.clone() }
```
```rust
/// Converts from `Result<Result<T, E>, E>` to `Result<T, E>`
pub fn flatten(self) -> Result<T, E>;
try { x?? }
```
## Future possibilities:
`as_deref` and `as_deref_mut` might be possible with deref patterns.
The various `or` and `unwrap_or` and `map_or` and similar functions may be
possible with some kind of coalescing operation. I'd prioritize that below `is`
and `try` though.