For one thing, the pattern matching used in Erlang, ML, and Haskell can be quite easy to read.
For example, something like
let days_in_month m = match m with
| Jan | Mar | May | Jul | Aug | Oct | Dec -> 31
| Apr | Jun | Sept | Nov -> 30
| Feb -> if leap_year () then 29 else 28
It takes a small amount of context (all "| Val" sections without a -> ... side match together), but it's a pretty direct correspondence.
That's not much harder in C or Java, given appropriate enum declarations:
public int days_in_month(month) {
switch(month) {
case JAN:
case MAR:
case MAY:
case JUL:
case AUG:
case OCT:
case DEC:
return 31
case APR:
case JUN:
case SEPT:
case NOV:
return 30;
case FEB:
if(leap_year()) return 29; else return 28;
}
}
Pattern-matching really shines when you need to destructure the argument, then do something similar to the result regardless of which case resulted in the destructuring. For example, compare red-black trees written in Java:
I couldn't think of a better example at the time. Something that simultaneously matched several fields (whether destructured from one variable or not) and/or had guards would be a better example.
Maybe something like this (in pseudo-ML):
(* Look up order code for a Sci-Fi GadgetTM, units are in cm *)
let gadget_order_code width depth height color has_laser =
match (width depth height color has_laser) =
(* The original, simple code *)
| 5, 2, 1, Red, true -> "ZAP-X"
(* Most common width, color *)
| 4, d, h, Blue, true -> sprintf "ZAP-4-%d%d+" (str d) (str h) "+"
(* C for Custom Color *)
| 4, d, h, c, false -> "ZAP-4C-%d%d-%c" (str d) (str h) (color_code c)
(* Orange lasers are discontinued *)
| w, d, h, c, true when (w + d + h) < 15 and c != Orange ->
"ZAP-S-%d%d%d-%c" (str w) (str d) (str h) (color_code c)
| _, _, _, _, _ -> failwith "Unavailable"
That's a little complicated to determine with pattern matching or via a database, but doing it in a series of nested if statements would get mind boggling.