https://thedav.is/post/rusts-poor-composability/ Home Rust's Poor Composability Apr 05, 2023 * 3 min * Rust * PLT * Engineering * Pet-Peeves --------------------------------------------------------------------- I love Rust. I wish they would spend more time making it actually work for non hello-world use-cases. Iteration Rust has a nice pretty syntax for iterating: for x in &mut something { *x = (*x) * 2; } EXCEPT when you need to do anything else to the iterator, then its ugly: for (i, x) in something.iter_mut().filter(|| {...}).enumerate() { *x = (*x) * i } What's the point of having the 'pretty' syntax if it only works in the simplest of cases? I hate syntax that only works in hello world examples. It infuriates me, because it means that this is all just Oz, and that you eventually need to pull back the curtain and everything you were promised was a lie. Trying... Rust has a great syntax for early return on Err cases. let thing: Result = x.foo(); // Will return early with the error if x.foo() returns Err. let thing: A = x.foo()?; BUT when you try to use it with iterators -- which are also amazing, I love using iterators -- IT DOESNT WORK. // ? in an Iterator method doesnt work!! What the hell! let res: Vec<_> = iterator.iter().map(|x| x.foo()?).collect(); So instead we need to use the ugly for-loop manual collection let res = vec![]; for x in &iterator { res.push(x.foo()?); } In my mind, the for loop syntax should be simple syntactic sugar for iterator.iter().for_each(BODY), not bespoke syntax. The fact this breaks wrecks my mental model. Whats the point of having two completely different iteration syntaxes with different properties? But this also happens elsewhere, because of this ugly inflexability, we cant do: let z = x.foo().map(|y| y.bar()?); we must do let z = if let Some(y) = x.foo() { y.bar()? } Gross. The Rust designers really should have ran import this. There should be one-- and preferably only one --obvious way to do it. Again, the absolute lack of composability is astounding. Whats the point of even having iterator methods if you can't use them for real world usecases, where code is regularly fallable, so you need to return a Result. Async This is basically the same problem as before, but with .await instead of ?. You must use the for loop syntax if you want to use .await, because iterators are not powerful enough to support real world use-cases. Conclusion I have been a fan of Rust for 10 years now (wow!), and I love it. But the teams working on language design need to SLOW DOWN and focus on ergonomics and composability. Not adding new syntax because some other language has it. For years now there has been calls for a 'fallow year' for Rust, and I think it should happen. Of course, there are so many people working on Rust, it is infeasable to task everyone on 'ergonomics', but I think it should be the focus at least. Niko has some ideas but they still seem so lofty compared to basic ergonomic capabilities. There is some work on keyword generics that looks horrendous, but maybe would solve this problem. I hope they can work on it. TODO: reference registers of Rust -- https://without.boats/blog/ the-registers-of-rust/ TODO: Find the keyword generics work, link to it. --------------------------------------------------------------------- * Home * Posts * About * Works * GitHub- (c)2017-2023 Davis Silverman Creative Commons License