News for hackers. Stuff that matters.
Re:Rust's Poor Composability by overthrow on Thursday April 06, 2023 @10:38AM (#35468885)
> 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.
Re:Rust's Poor Composability by tempusr on Thursday April 06, 2023 @10:46AM (#35469017)
It 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.

Re:Rust's Poor Composability by unshavedyak on Thursday April 06, 2023 @10:49AM (#35469065)
Yea, 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.

Re:Rust's Poor Composability by mcronce on Thursday April 06, 2023 @10:51AM (#35469085)
Also,

  let res = iterator.iter().map(|x| x.foo()).collect::<Result<Vec<_>, _>>()?;
Re:Rust's Poor Composability by fnordpiglet on Thursday April 06, 2023 @11:59AM (#35470281)
I love rust because it satisfies my inner perl
Re:Rust's Poor Composability by tmtvl on Thursday April 06, 2023 @06:47PM (#35475559)
And people complain about ))) in Lisp...
Re:Rust's Poor Composability by y7 on Thursday April 06, 2023 @11:02AM (#35469268)
Does this early exit on error?
Re:Rust's Poor Composability by nimih on Thursday April 06, 2023 @11:22AM (#35469600)
Yes. You can prove it to yourself with this program: https://play.rust-lang.org/?version=stable&mode=debug&editio...
Re:Rust's Poor Composability by linkdd on Thursday April 06, 2023 @11:03AM (#35469272)
The 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!

Re:Rust's Poor Composability by chrismorgan on Thursday April 06, 2023 @11:10AM (#35469381)
Incorrect: collecting to a Result stops on the first error, as documented explicitly in https://doc.rust-lang.org/std/result/enum.Result.html#method....
Re:Rust's Poor Composability by tuetuopay on Thursday April 06, 2023 @11:11AM (#35469395)
Map and friends are lazy, so the whole chain is run once and in full for each item. Collect will short circuit at the first Err encountered. You can even try it out by using `.inspect()` in the chain to see that the iterations don't go past the first error.
Re:Rust's Poor Composability by nynx on Thursday April 06, 2023 @11:09AM (#35469364)
Collecting into a result will short circuit.
Re:Rust's Poor Composability by NobodyNada on Thursday April 06, 2023 @11:10AM (#35469386)
That's not true: 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
Re:Rust's Poor Composability by remram on Thursday April 06, 2023 @11:15AM (#35469452)
Short-circuit refers to stopping not skipping.
Re:Rust's Poor Composability by fnordpiglet on Thursday April 06, 2023 @12:01PM (#35470312)
I don’t understand. The example you replied to stopped, not skipped.
Re:Rust's Poor Composability by aPoCoMiLogin on Friday April 07, 2023 @09:38AM (#35481437)
that should print 4 and 5 if that was skipping ?
Re:Rust's Poor Composability by remram on Friday April 07, 2023 @12:10PM (#35483220)
Yeah I read too fast.

One of the issues with type inference, this exact same code does different things depending on whether the result is assigned to `Option<Vec<i32>>` or `Vec<Option<i32>>`

Re:Rust's Poor Composability by SuperCuber on Thursday April 06, 2023 @11:12AM (#35469412)
Re:Rust's Poor Composability by anon291 on Thursday April 06, 2023 @11:10AM (#35469378)
Realistically, 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.
Re:Rust's Poor Composability by sshine on Thursday April 06, 2023 @11:50AM (#35470102)
It 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.

Re:Rust's Poor Composability by WirelessGigabit on Thursday April 06, 2023 @06:10PM (#35475219)
It'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.

Re:Rust's Poor Composability by throwawaymaths on Thursday April 06, 2023 @08:30PM (#35476501)
Considering the author has been using rust for 10 years (if we believe them) I think it's saying something