Is `ref` more powerful than match ergonomics?

Also, there are cases where match ergonomics don't work, a simple example:

if let Some(x) = self.foo.as_mut() {
    x.mutate();
    return x
}

self.foo = Some(bar());

match self.foo.as_mut() {
    Some(x) => return x,
    None => unreachable!()
}

Which would work if you did

if let Some(ref mut x) = self.foo {
    x.mutate();
    return x
}

self.foo = Some(bar());

match self.foo {
    Some(ref mut x) => return x,
    None => unreachable!()
}

playground, while yes it is possible to rewrite this exact code to work (as seen in works_1), it may not always be feasible. For example, if you are using a custom enum with a large number of variants.

In any case, the fact that matches use place expressions has already been documented in the reference here

A match behaves differently depending on whether or not the scrutinee expression is a place expression or value expression. If the scrutinee expression is a value expression, it is first evaluated into a temporary location, and the resulting value is sequentially compared to the patterns in the arms until a match is found. The first arm with a matching pattern is chosen as the branch target of the match , any variables bound by the pattern are assigned to local variables in the arm's block, and control enters the block.

When the scrutinee expression is a place expression, the match does not allocate a temporary location; however, a by-value binding may copy or move from the memory location. When possible, it is preferable to match on place expressions, as the lifetime of these matches inherits the lifetime of the place expression rather than being restricted to the inside of the match.

(emphasis mine) This bolded text shows precisely why we can't switch over to match ergonomics, as it would be less expressive.

5 Likes