5 ms·
> BUT when you try to use it with iterators -- which are also amazing, I love using iterators -- IT DOESNT WORK. Yes it does let res: Result<Vec<_>, _> = it
by overthrow 3y ago
> BUT when you try to use it with iterators -- which are also amazing, I love using iterators -- IT DOESNT WORK.
Yes it does
let res: Result<Vec<_>, _> = iterator.iter().map(|x| x.foo()).collect();
let res = res?;
> But this also happens elsewhere, because of this ugly inflexability, we cant do:
Use and_then:
let z = x.foo().and_then(|y| y.bar())?;
I get that there's an upfront cost to learning this stuff, but I think he's blaming the language a little too aggressively.
- tempusr 3y agoIt just reads better in terms of code. `let res: Result<Vec<_>, _> = iterator.iter().map(|x| x.foo()).collect();` Left to right reading this statement is "iterate over the values and map it to the output of foo for each value. Then collect that map into a vector." His other example ``` for (i, x) in something.iter_mut().filter(|| {...}).enumerate() { x = (x) * i } ``` can also be read from left to right as "iterate over something, then filter and enumerate the values" It's much more explanatory than top down structures with 10 lines to explain the same thing.
- unshavedyak 3y agoYea, it's a game i often play. "Boy it would be nice if i could do X" where X is something like `and_then`, and then i go look it up in the stdlib and.. it's there. For a good while my X's were a nightly only experimental API, but slowly and surely they make it into stable. (Hash|Btree)Map's `.entry` methods (and friends) were another example. Generally speaking these methods are super helpful and someone else already thought of it. From my experience at least. .. also this article was infuriating hah.
- mcronce 3y agoAlso, let res = iterator.iter().map(|x| x.foo()).collect::<Result<Vec<_>, _>>()?;
- fnordpiglet 3y agoI love rust because it satisfies my inner perl
- tmtvl 3y agoAnd people complain about ))) in Lisp...
- y7 3y agoDoes this early exit on error?
- nimih 3y agoYes. You can prove it to yourself with this program: https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=e0fb377d0c81a3a2783025e590d0c81f https://play.rust-lang.org/?version=stable&mode=debug&editio...
- linkdd 3y agoThe problem with .map().collect()? is that it does not short-circuit. Consider: for item in iterable.iter() { item.foo()?; } You will exit the loop as soon as there is an error. But with .map().collect(), you iterate over the whole list, and then exit if one of the items yield an error. EDIT: Thank you for your answers, it seems I was wrong and it does short-cricuit!
- nynx 3y agoCollecting into a result will short circuit.
- anon291 3y agoRealistically, the 'problem' is that many programmers today get scared away when you start mentioning monads or effect systems. Realistically though, the solution is to have first class monads or effect systems in rust and other languages. A lot of language design today is 'wasted' in the sense that we spend time implementing special cases (Promises in javascript, ? syntax in rust, async syntax in rust) without any thought given to the meta problem. In my opinion, the lack of attention to the meta problem is due to programmers being scared of such topics.
- chrismorgan 3y agoIncorrect: collecting to a Result stops on the first error, as documented explicitly in https://doc.rust-lang.org/std/result/enum.Result.html#method.from_iter https://doc.rust-lang.org/std/result/enum.Result.html#method....
- NobodyNada 3y agoThat's not true: https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=226af340b7c47f3ccf25024049f595f6 https://play.rust-lang.org/?version=stable&mode=debug&editio... let v: Option<Vec<i32>> = (0..5).map(|i| { print!("{i} "); if i == 3 { None } else { Some(i) } }).collect(); // prints 0 1 2 3
- remram 3y agoShort-circuit refers to stopping not skipping.
- sshine 3y agoIt is a non-obvious Rust-ism that if you’re doing something with iterators and you don’t know how, it’s probably .collect(). ;-) Kind of like how the answer is always ‘traverse’ in Scala. .collect() gets overloaded a lot to deal with the intricacies of the return type, which usually says a lot about the computation, e.g. Result or HashSet.
- WirelessGigabit 3y agoIt's not the same. Using the question mark in a closure in general is confusing. Doing ? on the return value of a statement doesn't make sense. Normally ? is used for: here is this Result (I forgot the trait's name), and give me the Ok(), and if it is Err() then RETURN to the caller. So the function itself must be of type Result<_, _>. With the lambda in the example it is unclear by reading the code what the ? should do. Stop at the first error and return Err? Or should the return value be Result<Vec<_>, _>? One can use the try_ functions on an iterator.
- throwawaymaths 3y agoConsidering the author has been using rust for 10 years (if we believe them) I think it's saying something