<- ^ ->
Case guards

15  Case guards

case allows additional condition to be checked if pattern matches. This is called case guard. Example:
        switch x {
        case Int(i) if (i > 0): print_int(i)
        case Int(i):            print_int(-i)
        case _:                 skip;
        }
is the same as:
        switch x {
        case Int(i): if (i > 0) print_int(i)
                     else print_int(-i);
        case _:      skip;
        }
Although it might not seem very bright at the first glance it comes in handy in more complex cases, like:
        switch x {
        // special case negative Ints 
        case Int(i) if (i < 0):  print_string("small")
        // don't special case negative Int2s and Int3s, also treat
        // non-negative Ints ordinarily
        case Int(i):
        case Int2(i):
        case Int3(i):             print_int(-i)
        // ignore the rest
        case _:                   skip;
        }

15.1  Name binding and case guards

All variables bound by pattern are available in scope of case guard, for example:
        switch x {
        case Int(i) if i > 0:   // one can use i in condition
        case Bool(_):
                // but using i here would be error
                print_string("positive or bool");
        case _:
                skip;
        }
However beware cases like:
        switch x {
        case Int(y) if y > 0:
        case String(y) if String::length(y) == 3:
                // Compiler thinks y should be bound here, but this code
                // fails to typecheck.
                skip;
        case _:
                skip;
        }
which should be:
        switch x {
        case Int(i) if i > 0:
        case String(s) if String::length(s) == 3:
                // all ok
                skip;
        case _:
                skip;
        }

15.2  Case guards and pattern exhaustiveness

Compiler assumes each case guard can fail for purposes of exhaustiveness warnings, for example it will complain about:
        int i;
        // ...
        switch i {
        case x if x > 0:        return 1;
        case x if x <= 0:       return 2;
        }
that it is not exhaustive, although it is. The correct way to write this is:
        int i;
        // ...
        switch i {
        case x if x > 0:        return 1;
        case x:                 return 2;
        }
(although if would be surly more convenient in this case :-).

<- ^ ->
Case guards