Rust needs evert(), which turns an iterator over Result of T into a Result of a collection of T or a collection of errors
currently the most ergonomic way to do this is to wrap a whole pipeline in a function boundary and use `?`.
@tindall Slightly convoluted example 😅 https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=40c3c3a95425f621d643afb0bff01f0f
@kookie yeah! But it doesn't collect the errors, it just gives up on the first one
I'm thinking of something like how Rails validations give you all the errors that came up at each step
@tindall Ooooh that's what you meant. Yea, I have written a bunch of fold combinators for errors before and wish the stdlib had something for this.
... maybe we should work on a PR together 👉👈
@tindall i guess from_iter() is out, then, since you want a collection of errors instead of just the first one
@QuietMisdreavus yeah that's the issue... this would be another nice use for higher kinded types, tbh, because you could do it with any collection of a type with left and right variants
@tindall something like this: https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=a237de23eacfdfe3aecddbbe637e2316 maybe?
Just hacked this together, absolutely not efficient or anything, but ergonomic to use I guess...
I slightly modified @musicmatze's example and made it generic over the "collectable" collection, so you can now collect into Vec, LinkedList etc.
It now basically works a bit like std `collect()`.
@musicmatze @tindall What's not optimal about the solution is, that we allocate a whole `Vec` first only to then call from_iter() in the end to turn it into our desired collection type, so we allocate two collections.
I've dabbled some more and come up with the following, probably more efficient, solution:
@janriemer @tindall I guess the implementation can be simplified massively using Iterator::partition (https://doc.rust-lang.org/stable/std/iter/trait.Iterator.html#method.partition)
But I was too lazy to try it out.
@musicmatze @tindall Ah, thanks.
Not sure about the "simplified massively" part, though:
- partition requires that returned values implement Extend, so the additional trait bound needs to stay unfortunately
- we would need to move the bool "any_err" into the closure of `partition`, which would introduce a "side effect" -> imperative style then is probably more appropriate here
- also, there is an overhead of collecting Ok() values, although we might have Err() value already
I wonder, though: If one wants to collect either a result or all errors, the results are processed anyways... so why not return them? This way the caller can decide what to do with them. Yes, this means more allocation, but also more ergonomics IMO.
I think she is talking about this functionality which already exists. It is not very intuitive though.
let res = my_collection
So it turns a Vec<Result, Error> into Result<Vec<T>, Error>, and you can turn it into Vec<T> simply with ?. Otherwise you would probably need a for loop.