Warning
This post was published 33 days ago. The information described in this article may have changed.
On the chance of starting a bike shedding topic, I wanted to ask a simple, but serious question: Why are most methods of Iterator
so complex?
I mean, they're not hugely complex, but let's look at find_map()
for example:
fn find_map<B, F>(&mut self, f: F) -> Option<B>
where
Self: Sized,
F: FnMut(Self::Item) -> Option<B>,
{
#[inline]
fn check<T, B>(mut f: impl FnMut(T) -> Option<B>) -> impl FnMut((), T) -> ControlFlow<B> {
move |(), x| match f(x) {
Some(x) => ControlFlow::Break(x),
None => ControlFlow::Continue(()),
}
}
self.try_fold((), check(f)).break_value()
}
I can understand what's going on here. And I understand if you like functional programming, then yes, most utility functions defined on the Iterator
trait are expressible as try_fold()
.
But wouldn't the following be much simpler still?
fn find_map<B, F>(&mut self, f: F) -> Option<B>
where
Self: Sized,
F: FnMut(Self::Item) -> Option<B>,
{
while let Some(x) = self.next() {
if let Some(x) = match f(x) {
return Some(x);
}
}
None
}
No messing around with ControlFlow
, no internal closure, no call to another method. Just very plain control flow that you can see almost instantly is correct.
I can understand that maybe the code was written that way one day, and no one saw a reason the rewrite it. After all, with zero cost abstractions, it might not really matter.
But does it really not matter? In my debug builds, I can see that try_fold()
is a separate function call in my stack traces. Those builds could probably be sped up with a simpler implementation. And maybe it could improve compile times too. Maybe it would be negligible on the whole, but there's a whole bunch of methods that are like this: all()
, any()
, find()
, find_map()
itself, position()
, rposition()
, try_find()
, comparison methods, maybe more? Seeing how pervasively iterators are used in Rust, maybe simplifying this code is worthwhile, even if the gains are minuscule?
But it begs the question: Am I missing some reason for why using try_fold()
is actually better?
4 posts - 2 participants
🏷️ rust_feed