Skip to content

ACP: Add Option::reduce #609

Open
Open
@orlp

Description

@orlp

Proposal

Problem statement

I regularly run into the situation where I have two Options, and I'd like to combine them in some way. This almost always takes the the following form:

match (l, r) {
    (Some(l), Some(r)) => Some(f(l, r)),
    (Some(l), None) => Some(l),
    (None, Some(r)) => Some(r),
    (None, None) => None,
}

This is rather verbose for ultimately something very simple.

Motivating examples or use cases

Searching for (Some(l), Some(r)) => on Github already gives dozens and dozens of matches for this pattern, even when looking for specific variable names (l and r). Not all results (or even most) of this query match this pattern, but there is still a lot of matches for it.

Solution sketch

I think we should add the following function to Option<T>:

impl<T> Option<T> {
    pub fn reduce<F: FnOnce(T, T) -> T>(self, other: Option<T>, f: F) -> Option<T> {
        match (self, other) {
            (Some(l), Some(r)) => Some(f(l, r)),
            (Some(l), None) => Some(l),
            (None, Some(r)) => Some(r),
            (None, None) => None,
        }
    }
}

I'm open to other names than reduce, it just seemed follow Iterator::reduce closely.

Alternatives

There is the following alternative,

l.into_iter().chain(r).reduce(f)

but this is quite a bit longer and less readable/clean in my opinion (and also requires a FnMut). There is also the micro-crate opt_reduce which adds precisely this method in an extension trait.

Unlike a lot of other methods on Options, it is not possible to neatly express this method using ? short-circuiting. The status quo essentially always boils down to the above verbose match statement. If you know your pattern jutsu well you can avoid one extra match arm (but I'm not sure if it's actually more readable):

match (l, r) {
    (Some(l), Some(r)) => Some(f(l, r)),
    (Some(x), None) | (None, Some(x)) => Some(x),
    (None, None) => None,
}

Links and related work

This has been discussed and closed before:

Nevertheless, I still run into this pattern a lot and I think Option::reduce is quite a natural addition to the standard library, so I'm bringing it up again.

Metadata

Metadata

Assignees

No one assigned

    Labels

    ACP-acceptedAPI Change Proposal is accepted (seconded with no objections)T-libs-apiapi-change-proposalA proposal to add or alter unstable APIs in the standard libraries

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions