Skip to content
Kavachकवच

Match

Also known as: match switch case pattern matching when enum exhaustive

● Beginner4 minBefore this: If...ElseSpec 4.3

match compares a value against patterns, top to bottom, and runs the first that fits.

Syntax

match value {
    pattern => result
    pattern => result
    _ => result      // anything else
}
syntax: Kavach code

Example

fn main() {
    const day = 6
    const name = match day {
        1 => "Monday"
        6 => "Saturday"
        7 => "Sunday"
        _ => "a weekday"
    }
    print(name)
}

The program ran and printed:

kavach run values.kav

Saturday
values.kav: Kavach code, then what running it prints

Like if, a match is a value. _ matches anything, so it goes last.

Every case, or an error

A match must cover every possible value. Forget one, and the compiler names it:

type Status = Pending | Paid | Refunded

fn label(s: Status) -> String {
    match s {
        Status.Pending => "waiting"
        Status.Paid => "done"
    }
}

fn main() {
    print(label(Status.Paid))
}

The compiler refused the program:

kavach run missing.kav

error: this `match` does not cover `Status.Refunded`
missing.kav: Kavach code, then what running it prints

An arm that can never match

Arms are tried in order too. An arm after one that matches everything is dead code, and the compiler says so:

type Size = Small | Medium | Large

fn label(s: Size) -> String {
    match s {
        _ => "any size",
        Size.Small => "small",
    }
}

fn main() {
    print(label(Size.Small))
}

The compiler warned, then the program ran:

kavach run never-matches.kav

warning: this arm never matches: the arm above it matches every value first. Remove it, or move it up (spec 4.7)any size
never-matches.kav: Kavach code, then what running it prints

In the editor, the quick fix "Remove this arm" takes out the arm's whole lines, comma included.

An arm that leaves

An arm may leave instead of giving a value: return, fail, break or continue. The match then has the value of the arm that was taken, and the code after it runs only when one that gives a value was:

type Share = Full | Half | Escalate

fn refund(price: Int, share: Share) -> String {
    const amount = match share {
        Share.Full => price,
        Share.Half => price / 2,
        Share.Escalate => return "escalate",    // leaves the function
    }
    "refund {amount}"
}

fn main() {
    print(refund(90, Share.Full))
    print(refund(90, Share.Half))
    print(refund(90, Share.Escalate))
}

The program ran and printed:

kavach run leave.kav

refund 90refund 45escalate
leave.kav: Kavach code, then what running it prints

In a loop, break stops the loop and continue goes on to the next round:

fn main() {
    let total = 0
    for x in [5, -3, 10, 200, 7] {
        const add = match x {
            _ if x > 100 => break,     // too big: stop the loop
            _ if x < 0 => continue,    // below zero: skip this one
            _ => x,
        }
        total += add
    }
    print(total)
}

The program ran and printed:

kavach run leave-loop.kav

15
leave-loop.kav: Kavach code, then what running it prints

200 stops the loop, so 7 is never added, and -3 is skipped: 5 + 10 is 15.

One page for each form

Try it yourself

Match a number from 1 to 3 to the words "one", "two", "three", and "many" for anything else.
Show the answer

Four arms: 1 => "one", 2 => "two", 3 => "three", and _ => "many" last.

What Kavach does for you

  • match covers every case

    Add a new variant to a union and the compiler lists every match that must now handle it. Nothing is forgotten silently.

    spec 4.3