Eager vs lazy evaluation

By Ludwig Pacifici
and
Tags: til lazy rust

TIL bool::then_some in Rust

While participating in Advent of Code, I learned about bool::then_some. Because I tried to finish the problem on time, I did not read fully the documentation. I wrote a get helper function to access an element in a 2D array. The code (simplified to 1D) looked like:

fn main() {
    dbg!(get(&vec![42, 51], 4));
}

fn get(v: &[u8], i: usize) -> Option<u8> {
    (i < v.len()).then_some(v[i])
}

It compiles fine, but it crashes:

thread 'main' panicked at src/main.rs:6:29:
index out of bounds: the len is 2 but the index is 4
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace

Cargo-Process exited abnormally with code 101 at Thu Feb 13 21:04:58

What is wrong with this code?

TIL bool::then in Rust

When the get function runs, regardless of the bound check, v[i] is eagerly evaluated (as it is an argument of the then_some function). That’s why bool::then exists; it relies on lazy evaluation via a lambda.

The below get function will not crash due to index out of bounds:

fn get(v: &[u8], i: usize) -> Option<u8> {
   (i < v.len()).then(|| v[i])
}

Note, this pattern is used in several places. As similar an example, consider Option::unwrap_or and Option::unwrap_or_else.

Finally, this is the real use case I stumbled upon while solving day 12 of Advent Of Code 2024.