Rust is very pleasant language to use because it catches most of your attempts to write invalid code. However, there are still several gotchas. One of them is match statement which behaves differently depending on whether some symbol is imported or not instead of giving clear error:
// comment this to change 'match' behavior'.
use std::fmt::Alignment::Left;
fn main() {
let value = Some(std::fmt::Alignment::Right);
match value {
Some(Left) => println!("left"),
_ => println!("other"),
}
}
Ok, Rust isn't completely silent here:
warning: variable `Left` should have a snake case name`
And fresh Rust even gives hard error:
pattern binding `Left` is named the same as one of the variants of the type `std::fmt::Alignment`
However, it all seems like heuristics instead of systematic solution.
There is another form of same problem:
let a = 2;
let n = Some(3);
match n {
Some(a) => println!("n == a"),
_ => println!("not equal"),
}
Behavior which many users expect here is:
let a = 2;
let n = Some(3);
match n {
Some(a) if a == n => println!("n == a"),
_ => println!("not equal"),
}
But there is no way to distinguish fresh binding from reference to existing one.
Then why not require explicit bindings in patterns?
match n {
Some(let a) => …
let other => …
}
Pros:
- Clear binding indication
- 'Identifier not found' instead of silent binding
- Easy to introduce in epoch, since only syntax is changed, not semantics
Cons:
- More verbose, sometimes more ugly (
&(let a)
)
What do you think of that? Are there any existing discussions/issues/rfcs on this topic?