OxigenLang Pattern Matching
OxigenLang features a powerful pattern-matching system using the pattern and choose keywords. Patterns define named, reusable conditions that can be matched against values.
#Defining Patterns
A pattern is a named condition taking a single parameter. Define patterns at the top level of your program using the pattern keyword:
pattern is_even(n) when n % 2 == 0
pattern is_odd(n) when n % 2 != 0
pattern is_positive(n) when n > 0
pattern is_large(n) when n > 100A pattern definition has three parts:
- Name: An identifier for the pattern (e.g.,
is_even). - Parameter: Exactly one parameter name in parentheses (e.g.,
(n)), which receives the subject value fromchoose. - Condition: A
whenclause with a boolean expression that references the parameter.
A pattern is always invoked with the single value being matched, so declaring any other number of parameters is an error:
pattern cmp(a, b) when a > b // error: a pattern takes exactly one parameter
pattern always() when True // error: no parameter to bind the matched value toTo compare against something else, capture it from the enclosing scope:
limit := 3
pattern big(n) when n > limitPatterns are registered globally and can be referenced by name in any choose block that follows.
#The choose Statement
choose evaluates a subject expression against one or more pattern arms. The first arm whose pattern matches is executed:
val := 42
choose val {
is_even -> println("Even"),
is_odd -> println("Odd")
}#How Matching Works
When choose val { is_even -> ... } is evaluated:
- The subject value (
val, which is42) is bound to the pattern's parameter (n). - The pattern's condition (
n % 2 == 0) is evaluated withn = 42. - If the condition is truthy, the arm's body executes.
- If not, the next arm is tried.
Arms are evaluated top to bottom. The first matching arm wins — subsequent arms are skipped.
#The else Arm
Use else as a catch-all default arm that matches when no other pattern does:
val := 42
choose val {
is_large -> println("Large"),
else -> println("Not large")
}If no arm matches and there is no else, the choose statement produces no value.
#Arm Bodies
Each arm's body is an expression. For multi-statement bodies, use a block:
choose val {
is_even -> {
println("Found an even number")
println("Value:", val)
},
is_odd -> println("Odd")
}#Inline Patterns
Patterns can be defined directly within choose arms instead of as separate top-level statements. This is useful for one-off conditions:
val := 42
choose val {
pattern is_even(n) when n % 2 == 0 -> println("Even"),
pattern is_large(n) when n > 100 -> println("Large"),
else -> println("Neither")
}Inline patterns follow the same syntax as top-level patterns but are written inside the arm before the ->.
#Mixing Pre-Defined and Inline Patterns
You can freely mix pre-defined (top-level) and inline patterns in the same choose block:
pattern is_even(n) when n % 2 == 0
val := 42
choose val {
is_even -> println("Even"),
pattern is_large(n) when n > 100 -> println("Large"),
else -> println("Neither")
}#Pattern Matching in Loops
Patterns are especially useful when iterating over collections:
pattern is_even(n) when n % 2 == 0
pattern is_odd(n) when n % 2 != 0
each num in range(10) {
choose num {
is_even -> println(num, "is even"),
is_odd -> println(num, "is odd")
}
}#Patterns with Multiple Parameters
Patterns can define multiple parameters, though only the first receives the choose subject:
pattern in_range(n) when n >= 0
pattern is_adult(age) when age >= 18#Practical Example: Classification
pattern is_negative(n) when n < 0
pattern is_zero(n) when n == 0
pattern is_small(n) when n > 0
pattern is_large(n) when n > 100
nums := [-5, 0, 42, 150]
each n in nums {
choose n {
is_negative -> println(n, "is negative"),
is_zero -> println(n, "is zero"),
is_large -> println(n, "is large (>100)"),
is_small -> println(n, "is small positive"),
else -> println(n, "unclassified")
}
}Note: Arm order matters. In the example above, is_large is checked before is_small because a large number would also match is_small (both have n > 0). Place more specific patterns first.
#Indentation Mode
Pattern matching works with both block styles:
#[indent]
pattern is_even(n) when n % 2 == 0
pattern is_odd(n) when n % 2 != 0
each num in range(10):
choose num:
is_even -> println(num, "is even")
is_odd -> println(num, "is odd")#choose vs option
Both choose and option provide branching, but they serve different purposes:
| Feature | choose | option |
|---|---|---|
| Purpose | Match a value against named patterns | Evaluate boolean conditions |
| Subject | Takes an explicit subject value | Each arm has its own condition |
| Arms | Pattern names or inline patterns | Boolean expressions |
| Default | else -> | Last arm without -> |
| Best for | Classifying a single value | Multi-way conditionals |
Use choose when you want to classify a value against named conditions. Use option when you have independent boolean conditions.
See also:
- Control Flow —
option,unless, and other conditionals - Data Types — types that can be used as
choosesubjects