Fairly new Rust user here–love the language, excited to have a chance to contribute!
I've come across a use case where I'm looking for a fallible version of the Map iterator, much like the version specified for arrays in #79711. I was originally thinking about a solution independent of anything related to Try, like:
Basically just an adapted version of the existing map that's "all-or-nothing" fallible: it either succeeds or fails in aggregate.
Would love to get opinions on either implementing the above "no-try" solution generically for iterators similar to map, or extending the solution proposed in the array-related tracking issue above. If it sounds like something worth pursuing, I'd love to give it a shot.
The fundamental complication here is the expectation that iterators are lazy. .map(...) just returns a Map<...> without actually running anything. There's no way to both be lazy and know immediately that something down the road is going to be an Err.
Would adding a rustdoc alias for try_map to collect potentially be helpful? Or perhaps to map, and add an example that uses collect::<Result<_, _>>.
Overall, discoverability of collect-to-Result still seems lower than ideal, especially for how useful it is.
Perhaps it's actually worth adding try_collect just as a helper for this. I believe Itertools has one, actually. Additionally because (especially when used with ?) you can often have to hint the the types involved, you'd be able to write try_collect::<Vec<_>, MyError> instead of collect::<Result<Vec<_>, MyError>> or collect::<MyResult<Vec<_>>>.
(Well, at least if it's only for Result and not any impl Try, which removes the hinting benefit. Though maybe makes it work with Try + !Collect types? I'm unsure how Tryv2 and Collect would interact for non-Result types.)
So like try_reduce just did, I think it could just be .try_collect::<Vec<_>>(), where the method would be fn try_collect<B>(&mut self) -> ChangeOutputType<Self::Item, B> -- and thus if the iterator's item is Option<T> the method would return Option<Vec<T>>, for an item type of Result<T, E> it'd return Result<Vec<T>, E>, and so on.
(The &mut self also helps distinguish this from collect -- you could resume using the iterator after the error, if you wanted.)
I very much might. (And I very much might not. If anyone else wants to beat me to the punch, please do, and stick a link in this thread.)
First, though, I need to experiment a bit with another Result-ish adapter. Specifically, Collect for Result as-is has the limitation that any yielded items before the error are just unretrievably dropped.
I want to at least see if it's possible to write a TResult<B, Item> where Item: Try, B: FromIterator<B::Output> that stores Result<B, (B, Item::Residual)> but implements Try<Output=B, Residual=Item::Residual>. Basically, ? as-if it were ChangeOutputType<Item, B>, but allow access to the output elements prior to the residual.
I don't know if we want to actually do it that way, but I'd like to have it for comparison against the simpler one.
Signatures
I did this without rustc to check my work so this is just to sketch the signatures slightly more formally:
Whoops, didn't realize there was still activity on my post since the initial discussion. I'd be interested in making a PR to implement try_collect as you've proposed, assuming no one else has done so already.
Just wondering what the process is for getting started on something like this: do I just jump right in and implement it/submit a PR, or are there other tasks I should take care of (e.g. making a tracking issue or something) in addition to actually writing the code?
Since it's just a single method, you can just send a PR. (If it was easier to write an RFC than the code, or if it was something like a trait that would affect all kinds of stuff, then you'd want to at least start a zulip thread or write an RFC before the code. But for a small addition you can just write it, use that for the discussion, then do anything else that's needed later.)