Thread with 9 posts
jump to expanded postWhen I need to find a minimum time, minimum screen co-ordinate, etc, I often find myself writing Rust code like this:
if let Some(new) = new {
current = Some(current.map(|i| i.min(new)).unwrap_or(new));
}
Is there a better way to do this? Even if it just covers the inner part (the case where new.is_some()), I’d love to know.
a friend told me about map_or, and made some other suggestions: https://twitter.com/mcpowr/status/1625080741657985025
ah, it’s possible to do the whole thing like this:
current.xor(new).or_else(|| current.zip(new).map(|(a, b)| a.min(b)))
but that’s far from elegant… having .zip_with() would help a bit.
this kind of reduction case can’t be that uncommon. I wonder if it would be a good candidate for a new function? no idea what to call it, definitely not .xor_or_zip_with() lol
neatest solution so far comes courtesy https://twitter.com/LambdaFairy/status/1625114170504118272
knowing Ord::max() does what we want for an Option, but Ord::min() doesn’t, then if we define an enum exactly like Option but with the variants in the reverse order, we get an enum for which Ord::min() will do the right thing (but Ord::max() doesn’t)
with that said… you should probably just use match (a, b) { and handle all four cases :p
@hikari sentient_rust_utils::do_the_specific_thing_i_need_done()
@elena oh I love that function, it even provides a formal proof that your code is correct and automatically uploads a paper it co-authored to arXiv
@hikari I'd go with .or_with(): It will result in Some when one or both of its operands are Some, so it's just a regular or and not an exclusive or.
@hikari Two options I can think of:
- match (current, new) { ... } and handle all Some/None combinations explicitly. Offers the best readability IMO, and results in the shortest machine code of all variants I checked.
- [current, new].into_iter().flatten().min(); Requires the workaround described in the Iterator::min() docs for floats though... and generates absolutely atrocious code.