-
Notifications
You must be signed in to change notification settings - Fork 340
Description
#780 (comment) by jswrenn
In the Rust standard library, it's quite common for
foldto be implemented in terms oftry_fold. In your original code you construct aTakeWhileand callfoldon it. ButTakeWhile's fold implementation delegates totry_fold!The general rule to follow is something like this:
If you need to completely consume an iterator, use
for_eachorfold.
- Use
for_eachif you don't need to maintain an accumulator.- Use
foldif you do need to maintain an accumulator.If you need to partly consume an iterator, use
try_for_eachortry_fold.
- Same rules about accumulators apply.
Bold is mine as I wonder if we are using for_each (convenient) at multiple places instead of fold.
Current for_each uses:
- lib.rs:
Itertools::{counts, partition_map, join} - extrema_set.rs:
min_set_impl - grouping_map.rs:
GroupingMap::{aggregate, collect} - group_map.rs:
into_group_map - k_smallest.rs:
k_smallest
(There is also Itertools::foreach but this one is okay.)
Why do I care? While benchmarking a new MapForGrouping::fold, I found out that some_slice_iter::for_each does not delegate to fold (default behavior) and is not optimized * (just while let Some(x) = self.next() { f(x); }) while some_slice_iter::fold is optimized (which is useful to see benchmark improvements of specializing fold methods of our adaptors by delegating to the inner iterator).
*: The for_each has a comment: "We override the default implementation, which uses try_fold, because this simple implementation generates less LLVM IR and is faster to compile."