Making patterns more ergonomic


#1

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.


#2

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

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!


#4

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;