Generalized switch statement (a la pattern matching)

Alex Rønne Petersen xtzgzorex at gmail.com
Thu Oct 27 05:05:43 PDT 2011


Hi,

Many functional languages have what is called pattern matching. That is, 
matching a value against a set of expressions, testing for exact equality.

For example, in F# (ML-ish) code:

let x = fooOrBarOrBaz()
match x with
| "foo" -> printf "got foo"
| "bar" -> printf "got bar"
| "baz" -> printf "got baz"

It's dead simple, and works more or less exactly like a switch: Walk 
through each case until a value matching x is found. Then, execute that 
branch.

There are three major differences, however:

1) If no match could be found, an exception (in D's case, this would be 
an Error-derived type) is thrown.
2) A 'default' branch is specified by matching against a plain variable 
(typically _ if unused). This always matches, since it's just a plain 
binding of the matched-against value to another variable.
3) The cases in the pattern match can be *any* expression. They don't 
have to be compile-time constants. This is extremely flexible, and some 
would argue that it is what the switch statement always should have 
been. Of course, the values in each case have to be compatible or 
implicitly convertible to the type of the value being matched against.

It is worth noting that pattern matching does not ruin compiler 
optimization of switches. It merely takes some extra effort to determine 
that all cases are constant.

Furthermore, point (2) naturally leads to the question: What happens if 
you match a value against an already-bound variable? In functional 
languages, what happens is typically shadowing (i.e. the already-bound 
variable becomes 'hidden'). In D, I think it would make more sense to 
match against the variable's value, since D doesn't have shadowing 
anywhere else AFAIK.

Additionally, binding the value to a new variable in the 'default' case 
might not make sense in D. When you hit the 'default:' label, you 
already have the switched-upon value in scope anyway.

Another trait of pattern matching in functional languages is that a 
pattern match is usually an expression. This means that whatever value 
is returned from the matched case (if any) is the result of the pattern 
match expression. I don't think that this would 'fit in' in D. Then we'd 
have to make if-then-else, while, for, foreach, do-while, etc 
expressions too, for consistency, which doesn't really seem at home in 
an imperative language.

Furthermore, there is the issue of introducing a new keyword. I don't 
think this is a good idea, especially not a common word like "match" or 
something along those lines (and __match would just be outright ugly).

So, I propose the following changes:

1) The switch statement should be generalized to allow any expression in 
cases. If the expression is an existing variable, the switched-upon 
value will be matched against the value of that variable. If the 
expression is an unbound variable, it is a compile-time error.
2) If no case is matched, and no 'default' case is present in the 
switch, an Error (say, SwitchCaseError or whatever) should be raised. I 
don't think this is a bad idea, since we're already moving towards 
deprecating lack of 'default' in non-final switches.

Point (1) is the most important one here. (2) is not crucial for good 
pattern matching capabilities, and is more of an aid in debugging.

What do you folks think? Would this have a place in D?

- Alex


More information about the Digitalmars-d mailing list