Skip to content

Tracking Issue for Iterator::try_collect #94047

Open
@a-lafrance

Description

@a-lafrance

Feature gate: #![feature(iterator_try_collect)]

This is a tracking issue for adding the try_collect() method to the Iterator trait, as originally discussed here. Iterator::try_collect() is a fallible variation of Iterator::collect() analogous to similar methods for reduce and fold, among others, that provides a simpler, generic way to collect iterators of Try elements into Try-wrapped types.

Difference from Iterator::collect

In terms of functionality, the main difference between try_collect() and collect() is that try_collect() allows you to fallibly collect iterators yielding types that implement Try but not FromIterator, which collect() can't do. Concretely this means you can try_collect() iterators yielding ControlFlow<_, i32> into ControlFlow<_, Vec<i32>>, which you can't do with collect().

It's also a &mut self method instead of collect's self, so that you can resume iteration after it early exits on an error. (Like how try_fold is &mut self while fold is just self.)

Another benefit of try_collect() is discoverability. Because the discoverability of the "collect-into-Result" appears to be lower than desired, "promoting" the technique into its own method seems like a good way to increase its discoverability and reach more users who would find it useful. (One of many examples of people just not being able to find the Option: FromIterator themselves: https://users.rust-lang.org/t/try-collect-as-iter-consuming-operation/20479?u=scottmcm.)

Finally, try_collect() presents a small ergonomics benefit in terms of type hints when collecting, namely that you only have to hint at the output type you're collecting into, not the whole Try type. For example, that means you can collect an iterator yielding Result<i32, SomeComplicatedError> with try_collect::<Vec<_>>(), as opposed to having to specify the whole Result with collect::<Result<Vec<_>, _>>().

Public API

trait Iterator {
    type Item;

    fn try_collect<B>(&mut self) -> ChangeOutputType<Self::Item, B>
    where
        Self: Sized,
        <Self as Iterator>::Item: Try,
        <<Self as Iterator>::Item as Try>::Residual: Residual<B>,
        B: FromIterator<<Self::Item as Try>::Output>;
}

Steps / History

Unresolved Questions

  • Should it have a more complicated signature to be able to return the partial results too? (@CAD97 https://internals.rust-lang.org/t/idea-fallible-iterator-mapping-with-try-map/15715/6?u=scottmcm )
  • Should it take self rather than &mut self, to prevent users from accidentally continuing to use the iterator after a try_collect() failure? Note that you can still continue to use the iterator if you use by_ref() first, so it's not necessarily a functionality change.
  • Does the name try_collect() conflict too much with the idea of collecting that's fallible in allocation? (i.e. collecting with Vec::try_reserve or similar)

Metadata

Metadata

Assignees

No one assigned

    Labels

    C-tracking-issueCategory: An issue tracking the progress of sth. like the implementation of an RFCT-libs-apiRelevant to the library API team, which will review and decide on the PR/issue.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions