Rust 2021

Minor major improvements

This is my response to the Rust Core Team's 2021 Roadmap call for blogs.

A year ago, stabilizing slice patterns was at the top of my wish list for Rust 2020. I'd been waiting for that for a long time. A few months later, it landed on the stable channel with release 1.42. I don't expect to be quite as lucky time around, but one can dream.

At the outset, I didn't really have any strong wishes for the next year. But when I sat down and thought about it, I came up with two things that I've run into lately that I know are being worked on and that I would love to see finalized.

Besides these two, there's const generics and GATs. High-profile features that get a lot of love in the community. The thing about these two, however, is that whenever I read up on them, they seem great and super useful, but I don't think I've actually run into any cases where I need them while programming. So while I hope the work on these continues, I want to turn my attention to two other points: nested OR-patterns and trait aliases.

Nested OR-patterns

This was mentioned as an upcoming feature in the post Recent and future pattern matching improvements from the Inside Rust Blog in March. In short, it allows you to nest patterns when pattern matching.

Imagine you have an Option<u8> and you want to check whether the possibly contained u8 is 4 or 13. Without using the or_patterns, you'd have to do something like this:

fn is_unlucky(n: Option<u8>) -> bool {
    match n {
        Some(4) => true,
        Some(13) => true,
        _ => false,
    }
}

Notice that double Some check? Using the or_patterns feature, we can simplify this:

// make sure you're on nightly!
#![feature(or_patterns)]

fn is_unlucky(n: Option<u8>) -> bool {
    match n {
        Some(4 | 13) => true,
        _ => false,
    }
}

As always, this is a simplified and contrived example, but it can simplify code considerably in some cases. And yes, I'm sure it can make some code even harder to read too, but that's a tradeoff I'm willing to make.

So where are we on this? There is an open tracking issue for it. But there seems to be some blocking issues at the moment, including one that makes the compiler panic, so I'm not sure what the status is. There hasn't been any activity on this since July, but I'm hopeful that we might see some progress on this in the coming year.

Trait aliases

Another feature that I've wished for at times is trait aliases (thanks to or Igor Aleksanov (popzxc) for mentioning this in their Rust 2021 post). This feature would allow you to refer to a collection of traits with an alias that you choose.

This is particularly nifty in situations where you use the same set of traits to define trait bounds over a number of functions. Instead of specifying the same combination over and over again, you can give the combination a name and use that name from there on.

Using Aleksanov's post as inspiration again, we could have something like this (without trait aliases):

trait MyTrait {}

fn f<T>(x: &T)
where
    T: MyTrait + Send + std::fmt::Debug,
{
    // do something with x here
}

fn g<T>(x: &T)
where
    T: MyTrait + Send + std::fmt::Debug,
{
    // do something else with x here
}

There are a few things about this code that could be improved with trait aliases. Most notably is the fact that the combination of the three traits we're using (MyTrait, Send, std::fmt::Debug) is repeated several times. It's not clear from the context whether these are intentionally or accidentally the same. If they are supposed to be the same, then when changing the combination one place, you'd have to remember to change it everywhere else. And while it's not necessarily bad, this combination is fairly verbose.

By using a trait alias, we can also give this combination of traits a more meaningful and descriptive name. This can help us better communicate to other developers (and to our future selves) why this combination is what it is.

Using the trait_alias feature on nightly, we can instead write it like this:

// again: you need to be on the nightly channel for this
#![feature(trait_alias)]

trait MyTrait {}

trait MyExtendedTrait = MyTrait + Send + std::fmt::Debug;

fn f<T>(x: &T)
where
    T: MyExtendedTrait,
{
    // do something with x here
}

fn g<T>(x: &T)
where
    T: MyExtendedTrait,
{
    // do something else with x here
}

At first, it might only look like we've added a line or two. But by grouping the trait combination under a new alias, we've ensured that the functions will change their trait bounds in lockstep. We have also given the trait combination a more meaningful name, though, admittedly, MyExtendedTrait isn't my strongest effort.

Much like with nested OR-patterns, there is a tracking issue issue for this. There seems to have been some activity back in March, but not much since.

That's it for now!

It's easy to just sit back and wish for new features when you're not the one implementing them. I'm very grateful to all the Rust teams for all their efforts, and I trust them wholeheartedly on what features to focus on in the coming year, whether they align with my wish list or not.

Rust continues to be one of the most exciting programming languages around and with one of the most welcoming communities to boot! As always: To everyone involved with the language, the ecosystem, and the community (and all the other parts that I'm forgetting): thank you very much. I'm looking forward to another year (and many more) with you!



Thomas Heartman is a developer, writer, speaker, and one of those odd people who enjoy lifting heavy things and putting them back down again. Preferably with others. Doing his best to gain and share as much knowledge as possible.