Is there any existing proposal about allowing multiple guards on a single pattern in a match
? I’m not using Rust in practice much, but I’d imagine using guards might become repetitive:
fn main() {
let y = Some(42);
let result = match y {
Some(x) if x > 0 => "some positive",
Some(x) if x < 0 => "some negative",
Some(x) => "zero",
None => "unknown",
};
println!("{}", result);
}
The repetition of Some(x)
would be problematic if the pattern was more complex. Coming from Haskell which also has pattern matching and guards and allows multiple guards per pattern, I’d enjoy syntax like this to become valid in Rust:
fn main() { /* Variant 1 */
let y = Some(42);
let result = match y {
Some(x) if x > 0 => "some positive",
else if x < 0 => "some negative",
else => "zero",
None => "unknown",
};
println!("{}", result);
}
While this particular example could be replaced also with
fn main() {
let y = Some(42);
let result = match y {
Some(x) => if x > 0 {"some positive"}
else if x < 0 {"some negative"}
else {"zero"},
None => "unknown",
};
println!("{}", result);
}
this is no longer an alternative if the guards are not exhaustive.
fn main() { /* Variant 1, non-exhaustive */
let y = Some(42);
let result = match y {
Some(x) if x > 0 => "some positive",
else if x < 0 => "some negative",
_ => "something else",
};
println!("{}", result);
}
Alternative Syntax Ideas
Since the else
above pretty much serves as a way to repeat a pattern without duplicating it syntactically, maybe some ellipsis sign like ..
(or something else) might be nicer
fn main() { /* Variant 2 */
let y = Some(42);
let result = match y {
Some(x) if x > 0 => "some positive",
.. if x < 0 => "some negative",
.. => "zero",
None => "unknown",
};
println!("{}", result);
}
or maybe nothing at all
fn main() { /* Variant 3 */
let y = Some(42);
let result = match y {
Some(x) if x > 0 => "some positive",
if x < 0 => "some negative",
=> "zero",
None => "unknown",
};
println!("{}", result);
}
well, that completely empty LHS of =>
might be a bit too much, so:
fn main() { /* Variant 4 */
let y = Some(42);
let result = match y {
Some(x) if x > 0 => "some positive",
if x < 0 => "some negative",
else => "zero",
None => "unknown",
};
println!("{}", result);
}
which is getting close to Haskell, where you’d be using guards in a syntax resembling this:
fn main() { /* Variant 5 */
let y = Some(42);
let result = match y {
Some(x) if x > 0 => "some positive",
if x < 0 => "some negative",
if true => "zero",
None => "unknown",
};
println!("{}", result);
}
This is however, perhaps, problematic regarding exhaustiveness checks.
Comparing to Haskell
For anyone unfamiliar with Haskell, here’s an example:
{-
Note: Haskell doesn’t have exhaustiveness checks (except as optional warnings)
The example below is using a definition from the standard library:
otherwise = True
[Read: “const otherwise: bool = true;”]
And it is using Haskell’s type `Maybe` which translates as follows:
Maybe ≙ Option
Just ≙ Some
Nothing ≙ None
-}
main = do
let y = Just 42
let result = case y of
Just x | x > 0 -> "some positive"
| x < 0 -> "some negative"
| otherwise -> "zero"
Nothing -> "unknown"
putStrLn result