Skip to content

Or Patterns, Ranges and Guards

Three extensions that cover most practical cases of value discrimination.

Or patterns: multiple alternatives

The | operator groups several patterns into a single arm. Instead of repeating the same body for each value, you list them separated by |. Works with literals of any type.

Days of the week, number parity and booleans with or-pattern.

04-or-patterns.zolo
Playground
// Feature: Or-patterns — multiple alternatives in one arm
// Syntax: `pat1 | pat2 | pat3 => body`
// When to use: group several inputs that trigger the same action,
// without repeating the body.

let day = "Saturday"
let kind = match day {
  "Monday" | "Tuesday" | "Wednesday" | "Thursday" | "Friday" => "weekday",
  "Saturday" | "Sunday" => "weekend",
  _ => "unknown",
}
print(kind)  // weekend

// Numeric.
let n = 5
let parity_or_special = match n {
  0 => "zero",
  1 | 3 | 5 | 7 | 9 => "small odd",
  2 | 4 | 6 | 8 => "small even",
  _ => "large",
}
print(parity_or_special)  // small odd

// Or-patterns with bool.
let flag = false
let label = match flag {
  true | false => "any",
}
// exhaustive in a single line
print(label)  // any
// expected:
// weekend
// small odd
// any

Numeric ranges

The start..=end pattern (inclusive on both ends) matches any number within the interval. Avoids listing each literal when the values form a contiguous block. Works with int and float.

Ranges to classify ages, grades and temperatures.

05-range-patterns.zolo
Playground
// Feature: Range patterns — numeric intervals
// Syntax: `start..=end` (inclusive)
// When to use: classify numeric values into ranges instead of
// listing each literal.

let age = 25
let group = match age {
  0..=12 => "child",
  13..=19 => "teenager",
  20..=64 => "adult",
  _ => "senior",
}
print(group)  // adult

// Scores -> letter grades.
let score = 87
let grade = match score {
  90..=100 => "A",
  80..=89 => "B",
  70..=79 => "C",
  60..=69 => "D",
  _ => "F",
}
print(grade)  // B

// Float ranges.
let temp = 22.5
let weather = match temp {
  -100.0..=0.0 => "freezing",
  0.0..=15.0 => "cold",
  15.0..=25.0 => "pleasant",
  25.0..=40.0 => "hot",
  _ => "extreme",
}
print(weather)  // pleasant
// expected:
// adult
// B
// pleasant

Guards: extra condition on the arm

A guard (pat if cond) adds an arbitrary boolean condition to the arm. The pattern is tested first; if it matches, the guard is evaluated — if it is false, the match engine tries the next arm. Guards are ideal for logic that ranges and literals cannot express (parity, comparison between fields, external predicates).

Parity, grades with score in the label and a guard combined with or-pattern.

06-guards.zolo
Playground
// Feature: Guards — extra `if expr` condition on the arm
// Syntax: `pat if cond => body`
// When to use: refine a pattern with logic that ranges/literals
// can't cover (parity, comparing fields, custom predicates).

let n = 12
let kind = match n {
  x if x < 0 => "negative",
  0 => "zero",
  x if x % 2 == 0 => "positive even",
  _ => "positive odd",
}
print(kind)  // positive even

// Guards with binding.
let score = 75
let grade = match score {
  s if s >= 90 => "A ({s})",
  s if s >= 80 => "B ({s})",
  s if s >= 70 => "C ({s})",
  s => "F ({s})",
}
print(grade)  // C (75)

// Guards combined with or-pattern — guard applies to the whole arm.
let day = "Sunday"
let busy = true
let plan = match day {
  "Saturday" | "Sunday" if busy => "weekend work",
  "Saturday" | "Sunday" => "rest",
  _ => "weekday",
}
print(plan)  // weekend work
// expected:
// positive even
// C (75)
// weekend work

Challenge

In the ranges example, add a 65..=100 => "senior" arm before the _ and remove the _. Run it and see whether the compiler accepts the match as exhaustive.

See also

enespt-br