# Early return after false condition

If often find myself writing code similar to this:

``````fn foo(...) -> Option<Foo> {
if condition1 { return None; }
if condition2 { return None; }
if condition3 { return None; }
let x1 = something1?;
let x2 = something2?;
let x3 = something3?;
Some(combineit(x1, x2, x3))
}
``````

The `?` operator is convenient here as it allows to shorten these repetitive blocks:

``````if something.is_none() { return None; }
let x = something.unwrap();
``````

But what about the condition checks?

``````if condition1 { return None; }
``````

Is there a convenient way to shorten and shortcut them for example with something like:

``````condition1?;
``````

Here is a real-world example:

``````fn cylinder_toi_pnt(&self, ray: &Ray, toi: f32, max_toi: f32) -> Option<(f32, Point3<f32>)> {
if toi <= 0.0 || max_toi <= toi {
None
} else {
let p = ray.point_at(toi);
if p.z < 0.0 || self.height < p.z {
None
} else {
Some((toi, p))
}
}
}
``````

Something like this would be shorter and easier to read imho:

``````fn cylinder_toi_pnt(&self, ray: &Ray, toi: f32, max_toi: f32) -> Option<(f32, Point3<f32>)> {
(toi <= 0.0 || max_toi <= toi)?;
let p = ray.point_at(toi);
(p.z < 0.0 || self.height < p.z)?;
Some((toi, p))
}
``````

This is a little bit like allowing conversion between `bool` and `Option<()>`.

You can do this conversion with `bool::then_some()`:

``````fn cylinder_toi_pnt(&self, ray: &Ray, toi: f32, max_toi: f32) -> Option<(f32, Point3<f32>)> {
(toi <= 0.0 || max_toi <= toi).then_some(())?;
let p = ray.point_at(toi);
(p.z < 0.0 || self.height < p.z).then_some(())?;
Some((toi, p))
}
``````

However, that's not especially idiomatic Rust and I would recommend using `if condition1 { return None; }` instead, unless your conditions are helper functions that you can just make return `Option<()>` directly to serve this purpose.

7 Likes

I agree `if condition1 { return None; }` is good enough, but if you use early return to do "continue with the value only when it is valid", then `Option::filter` would be natural.
However, it sometimes looks like "writing anything in one-liner" style even if it is valid usage...

``````fn cylinder_toi_pnt(&self, ray: &Ray, toi: f32, max_toi: f32) -> Option<(f32, Point3<f32>)> {
let toi = Some(toi).filter(|&toi| 0.0 < toi && toi < max_toi)?;
let p = ray.point_at(toi).filter(|&p| 0.0 <= p.z && p.z <= self.height)?;
Some((toi, p))
}
``````

This looks a lot like the `assert!` macro. Maybe write your own assert-like macro where you abstract `if condition { return None; }`? I think this (more or less) looks like idiomatic Rust:

``````fn cylinder_toi_pnt(&self, ray: &Ray, toi: f32, max_toi: f32) -> Option<(f32, Point3<f32>)> {
assert_or_none!(toi <= 0.0 || max_toi <= toi);
let p = ray.point_at(toi);
assert_or_none!(p.z < 0.0 || self.height < p.z);
Some((toi, p))
}
``````

`assert_or_none` could obviously be a function instead of a macro, like @kpreid suggested, but I like the orthogonality with std's `assert!`.

1 Like

The `error_stack` crate has `ensure!(cond)`, which runs `return Err { .. }` when `cond` is false.. which doesn't apply directly but I think "ensure" is a nice name for that..

2 Likes

So there is no way to implement the trait `Try` for `bool`? At least that's what the compiler suggests.

It would be possible for `core` to implement it, but it still wouldn't help you here, since it would only work in a method returning `bool`, not one returning `Option`.

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.