Rust 2021 Celebration and Thanks
github.com
github.com
This edition is deliberately "small" compared to Rust 2018, which was very large. That doesn't mean it wasn't a ton of work, as you can obviously see from the number of people and work done in this post, but it is more "quality of life changes" than "major new syntax and huge new features." More "stuff I expected to work that used to not work now works" and less "I need to learn this new shiny thing." Those of you who have been waiting for Rust to slow down a bit, this is one example of how that's happening.
Specifically, the various magical impls of From are a constant thorn in my side when writing practical rust. Specifically:
- Error messages if you screw something up with TryFrom tell you your problem was you implemented From<> wrong because of the magical `impl TryFrom<T, Infallible> for T where T: From` which is confusing as hell. I'm of the opinion this should be removed, and maybe add a macro for helping to implement it if you need/want that.
- The magical behaviour of `collect` when given a collection of results to produce a result with a collection causes me to work harder overall because it confuses the type inference to the point that you need to throw a type declaration into the most awkward places. This also happens because of an `impl From` that you can't get rid of. Sure, it's nice that occasionally it does something useful quickly and cleanly, but then it makes things confusing the other 80% of the time. Should just be a separate function.
let five_fives = std::iter::repeat(5).take(5);
// this:
let v: Vec<i32> = five_fives.collect();
// is equivalent to this
use std::iter::FromIterator;
let v = Vec::from_iter(five_fives);
if you prefer a function-like form.That functionality is incredibly useful though. I use it all the time.
But it's also really hard to discover. I've seen quite a few developers be both delighted and very surprised by the possibility.
I agree that an extension trait with a dedicated method (like `collect_result`) would probably be better, especially since rust-analyzer can now auto-import traits.
A lot of my opinion on this is informed by my experience in early-days Ruby and C++ with viable templates. It has the feel of the kinds of magic that I came to find very frustrating in both those languages.
The other thing is that fairly frequently my goal with collect isn't really to collect anything but to stop processing on an error. Sometimes I need to do this on a couple of layers and the intermediate vecs are gratuitous storage.
So my actual proposal would be more like having a simplified version of `scan` that's specifically for iters of results and then it's two steps: process-until-completion-or-error and eventually down the line collect-into-container if I actually want that.
Specifically, the weirdness here is that FromIterator<Result> is an implicit conversion between apple-and-oranges container types. Which is quite unlike most (or even all) other FromIterators and it has a complicated type relationship that makes everything else just slightly worse just to give people an ooh-ahh moment when rust does something they don't understand but is helpful.
Mostly some quality of life improvements.
Also note that the Rust compiler remains backwards compatible and continues to support all previous editions. (well, it's only 2015 and 2018 for now)
Lot's of work is put into the compiler, but a lot of it is refinement and plumbing at the moment. Big feature work has slowed down a lot (which is probably a good thing).
But as some positive news: GAT (generic associated types, a more restrictive variant of higher kinded types) are apparently nearing completion, which can also unblock some very important improvements for the async world (eg `async fn` in traits).
I do still really miss some big features though: async in traits, a more flexible dynamic trait system (multi-trait objects, downcasting), generators and specialization.