Pattern Matching
Pattern matching is a powerful control flow construct in Harneet that allows you to match values against patterns and execute code based on the match. It provides a more expressive and safer alternative to traditional switch statements.
Basic Syntax
The basic syntax for pattern matching uses the match keyword:
| Basic Syntax |
|---|
| package main
match value {
pattern1 => expression1,
pattern2 => expression2,
_ => default_expression
}
|
Pattern Types
Literal Patterns
Match against specific literal values:
| Literal Patterns |
|---|
| package main
var status = match code {
200 => "OK",
404 => "Not Found",
500 => "Server Error",
_ => "Unknown"
}
|
Wildcard Pattern
The underscore _ matches any value and acts as a catch-all:
| Wildcard Pattern |
|---|
| package main
var result = match value {
1 => "one",
2 => "two",
_ => "other" // Matches anything else
}
|
Variable Binding
Bind the matched value to a variable:
| Variable Binding |
|---|
| package main
var message = match number {
0 => "zero",
1 => "one",
n => "some number" // 'n' contains the matched value
}
|
Array Destructuring
Match and destructure arrays:
| Array Patterns |
|---|
| package main
var description = match coordinates {
[] => "empty",
[x] => "single point",
[x, y] => "2D point",
[x, y, z] => "3D point",
_ => "higher dimension"
}
|
You can also use specific values in array patterns:
| Array Value Matching |
|---|
| package main
var result = match point {
[0, 0] => "origin",
[x, 0] => "on x-axis",
[0, y] => "on y-axis",
[x, y] => "general point"
}
|
Blank Identifiers in Patterns
Use _ to ignore specific values in destructuring:
| Ignore Values |
|---|
| package main
var info = match data {
[_, _, important] => "third element is important",
[first, _] => "only care about first element",
_ => "other"
}
|
Guard Clauses
Add conditional logic to patterns using if guards:
| Guards |
|---|
| package main
var category = match age {
a if a < 13 => "child",
a if a >= 13 and a < 20 => "teenager",
a if a >= 20 and a < 65 => "adult",
a if a >= 65 => "senior",
_ => "unknown"
}
|
Guards can use any boolean expression:
| Complex Guards |
|---|
| package main
var grade = match score {
s if s >= 90 => "A",
s if s >= 80 => "B",
s if s >= 70 => "C",
s if s >= 60 => "D",
s => "F"
}
|
Array Pattern Examples
Basic Array Matching
| Basic Array Matching |
|---|
| package main
import fmt
var arrays = [[], [1], [1, 2], [1, 2, 3]]
for arr in arrays {
var description = match arr {
[] => "empty array",
[_] => "single element",
[_, _] => "pair",
[1, 2, 3] => "specific triple",
_ => "other array"
}
fmt.Printf("Array %s => %s\n", arr, description)
}
|
Array Destructuring with Guards
| Array Guards |
|---|
| package main
import fmt
var points = [[0, 0], [5, 0], [0, 3], [4, 3]]
for point in points {
var quadrant = match point {
[0, 0] => "origin",
[x, 0] if x > 0 => "positive x-axis",
[x, 0] if x < 0 => "negative x-axis",
[0, y] if y > 0 => "positive y-axis",
[0, y] if y < 0 => "negative y-axis",
[x, y] if x > 0 and y > 0 => "first quadrant",
[x, y] if x < 0 and y > 0 => "second quadrant",
[x, y] if x < 0 and y < 0 => "third quadrant",
[x, y] if x > 0 and y < 0 => "fourth quadrant",
[x, y] => "some point"
}
fmt.Printf("Point %s => %s\n", point, quadrant)
}
|
Real-World Examples
HTTP Status Code Processing
| HTTP Status Codes |
|---|
| package main
import fmt
var statusCodes = [200, 404, 500, 301, 401]
for code in statusCodes {
var status = match code {
200 => "OK",
201 => "Created",
301 => "Moved Permanently",
400 => "Bad Request",
401 => "Unauthorized",
404 => "Not Found",
500 => "Internal Server Error",
c if c >= 200 and c < 300 => "Success",
c if c >= 300 and c < 400 => "Redirection",
c if c >= 400 and c < 500 => "Client Error",
c if c >= 500 => "Server Error",
_ => "Unknown Status"
}
fmt.Printf("HTTP %d => %s\n", code, status)
}
|
Role-Based Access Control
| Role-Based Access |
|---|
| package main
import fmt
var roles = ["admin", "user", "guest", "moderator"]
for role in roles {
var access = match role {
"admin" => "full access",
"moderator" => "limited admin access",
"user" => "standard access",
"guest" => "read-only access",
_ => "no access"
}
fmt.Printf("Role '%s' => %s\n", role, access)
}
|
Type Safety and Exhaustiveness
Pattern matching in Harneet includes compile-time type checking:
- Pattern Compatibility: Patterns must be compatible with the matched value type
- Variable Binding Types: Variables bound in patterns get proper types
- Guard Validation: Guard clauses must be boolean expressions
- Return Type Consistency: All match arms must return compatible types
- Exhaustiveness Warnings: The compiler warns about potentially non-exhaustive matches
Best Practices
1. Always Include a Wildcard
| Include Wildcard |
|---|
| // Good - handles all cases
package main
import fmt
var result = match value {
"expected" => "handled",
_ => "fallback"
}
// Risky - may not handle all cases
var result = match value {
"expected" => "handled"
// Missing wildcard
}
|
2. Use Guards for Complex Conditions
| Use Guards |
|---|
| // Good - clear and expressive
package main
var category = match age {
a if a < 18 => "minor",
a if a >= 65 => "senior",
a => "adult"
}
// Less clear with nested conditions
if age < 18 {
category = "minor"
} else if age >= 65 {
category = "senior"
} else {
category = "adult"
}
|
| Use Destructuring |
|---|
| // Good - extract values directly
package main
var info = match coordinates {
[x, y] => fmt.Sprintf("Point at (%d, %d)", x, y),
_ => "Invalid coordinates"
}
// More verbose alternative
if len(coordinates) == 2 {
var x = coordinates[0]
var y = coordinates[1]
info = fmt.Sprintf("Point at (%d, %d)", x, y)
} else {
info = "Invalid coordinates"
}
|
4. Leverage Type Safety
Pattern matching provides compile-time guarantees about type safety and helps catch errors early in development.
Comparison with Switch Statements
Pattern matching is more powerful than traditional switch statements:
| Feature | Switch | Pattern Matching |
| Value matching | ✅ | ✅ |
| Variable binding | ❌ | ✅ |
| Destructuring | ❌ | ✅ |
| Guard clauses | ❌ | ✅ |
| Type safety | Limited | ✅ |
| Exhaustiveness checking | ❌ | ✅ |
Pattern matching provides a more expressive, safer, and more powerful way to handle conditional logic in Harneet programs.