Skip to content

Match and Type Guards

Chloë Strainge edited this page Oct 14, 2026 · 1 revision

Match and type guards

A match evaluates its subject once and selects the first matching arm. Each arm has a body scope, and its final result becomes the match's value.

let $priority = 4
let $expected = 9
let $description = match $priority
{
    0         => { "idle" }
    1..5      => { "routine" }
    $expected => { "reserved" }
    _         => { "urgent" }
}
echo $description
routine

Patterns can be literals, ranges, enum values, variables holding values or ranges, and ranges whose bounds are variables. .. excludes its end and ..= includes it. _ is an optional last fallback. Without a matching arm or fallback, match raises a runtime error rather than returning a guessed default.

Exact type tests

Every value has .type. Type names are values, and Type.name gives the name represented by a Type object. Identity tests are exact: a named Integer wrapper has its own type, and Number is not a wildcard type test.

let $reading: any = 12
match $reading.type
{
    Integer => { echo ($reading + 1) }
    String  => { echo $reading.trim }
    _       => { echo "other reading" }
}
if $reading.type == Integer && $reading > 10 { echo warm }
13
warm

The checker narrows a variable inside a matching type arm and along a true short-circuit && path. It can use the refined type to check arithmetic and member access. Named union interfaces can also narrow to a concrete member; unions explains which methods become available.

For absence, compare the value with () or its type with None. () is a value, not a synonym for the Type object named None.


Related: Enums · Control flow · Reflection

Clone this wiki locally