Skip to content

Instantly share code, notes, and snippets.

@Gankra
Last active June 16, 2017 00:41
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Gankra/95390640bac8418661561d0f472f9294 to your computer and use it in GitHub Desktop.
Save Gankra/95390640bac8418661561d0f472f9294 to your computer and use it in GitHub Desktop.

Rust RFC 2005 "Match Ergonomics" was just accepted. However there was a copy-paste error in the summary that led to some confusion about what it was actually doing. Here's a quick run down of the details that matter to users:

TL;DR version:

Before this change, matching on references works like this:

let by_ref: &MyEnum;
let by_mut: &mut MyEnum;

match  by_ref {  A(    x) => // Error: mismatched types
match *by_ref {  A(ref x) => // by reference
match  by_ref { &A(ref x) => // by reference 

match  by_mut {      A(        x) => // Error: mismatched types
match *by_mut {      A(ref mut x) => // by mutable reference
match  by_mut { &mut A(ref mut x) => // by mutable reference 

After this change, everything remains the same except these two now Just Work:

match by_ref { A(x) => // by reference
match by_mut { A(x) => // by mutable reference

Long version:

Before this change, there are many ways to precisely match a variable, and bind its contents. For instance, with these variables:

let mut by_val: MyEnum;
let by_ref: &MyEnum;
let by_mut: &mut MyEnum;

You get the following behaviours:

match by_val { A(        x) => // by value (move)
match by_val { A(ref     x) => // by reference 
match by_val { A(ref mut x) => // by mutable reference 

match  by_ref {  A(    x) => // Error: mismatched types
match *by_ref {  A(    x) => // Error: cannot move out of borrow  -- unless Copy, then by value (copy)
match *by_ref {  A(ref x) => // by reference
match  by_ref { &A(    x) => // Error: cannot move out of borrow  -- unless Copy, then by value (copy)
match  by_ref { &A(ref x) => // by reference 

match  by_mut {      A(        x) => // Error: mismatched types
match *by_mut {      A(        x) => // Error: cannot move out of borrow -- unless Copy, then by value (copy)
match *by_mut {      A(ref     x) => // by reference
match *by_mut {      A(ref mut x) => // by mutable reference
match  by_mut { &mut A(        x) => // Error: cannot move out of borrow -- unless Copy, then by value (copy)
match  by_mut { &mut A(ref     x) => // by reference 
match  by_mut { &mut A(ref mut x) => // by mutable reference 

After this change all cases remain the same, except these two cases now compile:

match by_ref { A(x) => // by reference
match by_mut { A(x) => // by mutable reference

FAQ:

What is the type of x in the new cases?

It's the same as if you used ref or ref mut -- &T or &mut T respectively.

Does the body of the match arm (how I use x) matter?

No. Only the pattern and the input type will be considered when deciding the type of x.

Can I accidentally mess things up because of this?

Potentially, but unlikely. There are two hypothetical scenarios where this will cause problems:

  • when you think you're using this new sugar, but aren't
  • when you think you aren't using this sugar, but are

Most cases will lead to some kind of error:

match by_val { A(x) => { x = y; } // error: x must be mutable, 
                                  // *or* later on -- error: by_val moved into x
match by_mut { A(x) => { x = y; } // error: expected &mut T, found T

The most plausible error would probably be:

// Thought we were making a copy and mutating that
match by_mut { A(x) => { x.y = z } // OK!

Note however that if the user remembered they should have to make x mut, they'll get a warning:

// Thought we were making a copy and mutating that
match by_mut { A(mut x) => { x.y = z } // warning: x is mutable but isn't mutated

And note that this typo is already possible:

// Oops forgot ref
match *by_mut { A(mut x) => { x.y = z; } // If T is Copy, OK -- writes to the temporary

So all in all, a careless developer can definitely shoot themselves in the foot, especially if they blindly add/remove refs/muts to get their code to work... but that was already true of patterns.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment