Rfcs: Have a function to convert boolean to Option<()> in std

Created on 25 Nov 2017  路  10Comments  路  Source: rust-lang/rfcs

Taking inspiration from haskell (http://hackage.haskell.org/package/base-4.10.0.0/docs/Control-Monad.html#v:guard), we could have a guard : fn(bool) -> Option<()> function in std

This lets us write more pleasant code. For example instead of

let x = do catch {
    if is_admin(user) {
        calculate_important_stuff()
    } else {
        None
    }
};

we can do this

let x = do catch {
    guard(is_admin(user))?;
    calculate_important_stuff()
};

basic implementation:

fn guard(b: bool) -> Option<()> {
    if b { Some(()) } else { None }
}

Or maybe even have a Try trait implementation for bool? Not sure if that's beautiful though

T-libs

Most helpful comment

I'd prefer having a .to_option method like this:

let x = is_admin(user).to_option(calculate_important_stuff);

All 10 comments

I'd prefer having a .to_option method like this:

let x = is_admin(user).to_option(calculate_important_stuff);

@CryZe, for this case, that indeed looks like a pretty solution. though! it's not as universal as guard, and I wouldn't really expect a function called to_X take any arguments (perhaps map_option or something?)

Why not impl From<bool> for Option<()>?

Previously in this genre...

Could bool just be defined as an alias for Option<()>? Correct me if I'm wrong, I think that Option<()> would already be represented as a 0 or 1 in memory, so this wouldn't break C compatibility.

@jasonhansel That would be backwards incompatible. People's crates may assume that bool and Option<()> are different types, so you may have one impl for bool, and one for Option<()>. Making them the same type would create overlapping impls. It might also affect type inference. We could perhaps do this change with a new epoch.

I used to think that a Try implementation for bool would be insane, but I'm coming around to it because it would fit really nicely for generalizing the || operator: https://internals.rust-lang.org/t/something-for-coalescing-aka-generalized-improved-or-else/9295/3?u=scottmcm

Edit: And if it did get or_else and and_then and such, then it really might as well support ?.

I've seen a few places where this would help reduce cruft like this, where a function checks a condition, and calls a function with an optional error, using a condition to determine if the error is there::

do_thing(index, if array[index] == 0 { Some(UnexpectedZeroError) } else { None });

With this implemented, I could reduce code like this to:

do_thing(index, Option::from(array[index] == 0).map(|| UnexpectedZeroError))

Even better for me, I'd love to see methods like or_some, or_else, and_some, and_else) added to bool:

do_thing(index, (array[index] == 0).or_some(UnexpectedZeroError);

(Even nicer for my case would be (array[index] == 0).or(UnexpectedZeroError), but I'm not sure whether people would be pleasantly or unpleasantly surprised by the fact that (a == 1).or(a == 2) returned Option<bool> and not simply bool.

Amusingly, this exists as Some(something).filter(|_| is_admin(user)). You'll want the short circuiting version though:

impl bool  { fn map_option<F: FnOnce() -> T>(self, F: F) -> Option<T> {..}  }

If you only have Option<()>: From<bool> then you've short circuiting with is_admin(user).into().map(|()| ..) but not sure if that .into() ever gets ambiguous.

This is available as condition.then_some(()) now. A method special-cased to () doesn't seem necessary in light of the more general method.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

camden-smallwood-zz picture camden-smallwood-zz  路  3Comments

yongqli picture yongqli  路  3Comments

mqudsi picture mqudsi  路  3Comments

onelson picture onelson  路  3Comments

clarfonthey picture clarfonthey  路  3Comments