Iterator's .sum() and .product() should mention that they work on iterators over Result<T,E> and Option<T> #105266
Labels
A-docs
Area: Documentation for any part of the project, including the compiler, standard library, and tools
Summary
It would be helpful if
Iterator
's.sum()
method would explicitly document that it can sum an iterator ofResult<T,E>
and produce aResult<T,E>
as output, and that it stops consuming the iterator when it hits the first error. To compound things, my mental model was a little off, and I didn't understand the compiler's diagnostics well enough to get nudged in the right direction.Likewise, it would be helpful to also document summing an
Option<T>
. Similarly, for.product()
andResult<T,E>
orOption<T>
. I'm not sure if there are other Iterator methods that also handleResult
andOption
similarly.Steps to Reproduce
If I go to the standard library documentation at https://doc.rust-lang.org/std/index.html, and then search for
sum
, then click onstd::iter::Iterator::sum
it gives an example of summing some integers. It would be helpful if this part of the documentation mentioned that you can also sum an iterator ofResult<T,E>
, which produces aResult<T,E>
where theOk()
variant contains the sum (if there were no errors), or theErr()
variant contains the first error. It would also be helpful to mention that it stops consuming the iterator once it encounters the first error.If I click on
Sum
in the declaration, it takes me to documentation of theSum
trait. In the Implementors section, there is a long list of implementations for various numeric types, theirWrapping
variants, their references,Wrapping
variants of references, SIMD stuff. At that point, my eyes glazed over, and I missed this one buried near the end:If I click the "source" link to the right of the above impl, the doc comments describe the behavior, and there is even an example (yay!). As far as I can tell, those doc comments aren't rendered on the documentation page for either the
Sum
trait, or the.sum()
method. It would probably be helpful to render them on the page for theSum
trait, and add a sentence or two to the documentation for.sum()
(perhaps link to theSum
documentation if you don't want to repeat it all).Background
This came about from the Advent of Code 2022, Day 1. See https://adventofcode.com/2022/day/1. The input is some text with groups of integers. The groups are separated by blank lines. Start by reading the input:
Now build a Vec where each element is the sum of the numbers in one group:
That works, but I'd like to do a better job of handling errors. First step is to change the function (
main
in this case) to return aResult<(), Box<dyn Error>>
, and add anOK(())
at the end of the function.Now, let's replace the .expect(...) with a question mark. My intent (for now) is to return from the function, not just the closure. I'm using VSCode with rust-analyzer. In the Problems tab, it says:
My first thought is that my function (main) does return Result. Oh, that last message is talking about the closure I'm passing to
.map()
. OK, let's tryreturn
instead:Lots of errors. First one says "closure bodies that contain statements must be surrounded by braces." I can do that (there's even a Quick Fix that adds them for me!). Now there are only 3 errors:
For that last error, it suggests wrapping the expression in
Ok()
. Let the Quick Fix do that. It wrapped the entire if-else insideOk()
. That still leaves the first error message:It never occurred to me that the closure could return a
Result
. After all, I'm trying to sum integers, so I assume my closure has to return an integer. That return statement I just added is returning from the closure, not the function. I go off to Google ways to return from a function from within a closure. I didn't find anything that looked promising.I take a different approach. Instead of using nested closures, I use nested
for
loops. Since it's not inside a closure any more, I can use the question mark to return from the function:That works, but there's got to be a better way. I figured out how to write a function that sums an iterator of
Result<T,E>
and produces aResult<T,E>
, and short circuits on the first error. I didn't know that.sum()
could already do this.I figured out how to turn that into a generic trait so I could use it as a method (like the methods in the Itertools trait). That took a bunch of fiddling with generics and bounds, but I was able to work through it (in large part because the diagnostics nudged me in the right direction). The final piece was figuring out how to write the
impl
block so I could replace.sum()
with my new.try_sum()
method.I knew that
.collect()
could transform an iterator overResult<T,E>
intoResult<Vec<T>, E>
, and therefore I can put a question mark or.expect()
after.collect()
.My implementation required the type I'm summing to implement
Default
andAddAssign
. Can I get rid of the need forDefault
? Should I depend onAdd
instead ofAddAssign
? I start digging through the implementation of.sum()
in the standard library to see if it does anything special that my implementation should. I ended up finding thatsum
(and other methods, likeproduct
) share a general purpose mechanism to handle iteration overResult<T,E>.
That means that.sum()
already does what my.try_sum()
does. I replace.try_sum()
with.sum()
and ... it works!The text was updated successfully, but these errors were encountered: