Making patterns more ergonomic

A while back there was talk about trying to make pattern matching (particularly when ref, match, and * are involved) more ergonomic and stumbled across a particularly annoying edge case which reminded me of it.

Is there any more news on this?

My particular example is that I’m iterating over a Vec<(usize, Bot)> and want to update each Bot. Currently I’ve got to write a big mess of &mut and ref to make the compiler happy:

for &mut (tok, ref mut bot) in &mut self.bots {
    let actions = bot.tick(&self.game_state);
    debug!("Bot {} executed {:?}", tok, actions);
}

Whereas it’d be much easier (and arguably just as understandable) if pattern matching could elide away the boilerplate so I can write something like this:

for (tok, mut bot) in &mut self.bots {
    let actions = bot.tick(&self.game_state);
    debug!("Bot {} executed {:?}", tok, actions);
}

In theory the compiler should be able to automatically dereference the tuple reference, then that because mut bot is trying to use a mutably borrowed thing it’ll automatically insert ref mut bot.

1 Like

I think this would be handled by RFC 2005 (Default binding mode) as well. Maybe comment on its tracking issue https://github.com/rust-lang/rust/issues/42640?

3 Likes

Hopefully in the future we’ll discuss how to extended that to all patterns, not only match, which would include for loops, fn/closure arguments, let bindings, etc…

But that would be a whole new RFC, so we should probably wait until we get more experience with only match.

Thanks @kennytm for the correction, glad to know the RFC already covers this!

RFC 2005 already covers all patterns. Note that the examples in the RFC involve let bindings. Also the current implementation (https://github.com/rust-lang/rust/pull/44614) works with OP's for loop.

https://github.com/rust-lang/rfcs/blob/master/text/2005-match-ergonomics.md#detailed-design:

Note that this RFC applies to all instances of pattern-matching, not just match expressions:

struct Foo(i32);
let foo = Foo(6);
let foo_ref = &foo;
// `foo_ref` is dereferenced, and `x` is bound like `ref x`.
let Foo(x) = foo_ref;
1 Like

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.