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
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.
Most helpful comment
I'd prefer having a .to_option method like this: