<- ^ ->
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