Control Flow
Mux provides familiar control flow constructs with some unique features like pattern matching with guards.
If / Else
Standard if-else branching with curly braces:
if x > 0 {
print("positive")
} else if x < 0 {
print("negative")
} else {
print("zero")
}
If as an Expression
In Mux, if can be used as an expression that returns a value:
auto message = if x > 0 { "positive" } else { "non-positive" }
auto status = if score >= 90 {
"excellent"
} else if score >= 70 {
"good"
} else {
"needs improvement"
}
For Loops
Mux uses range-based for loops only (no C-style for (int i = 0; i < n; i++)):
// Iterating over a list
auto items = [1, 2, 3, 4, 5]
for int item in items {
print(item.to_string())
}
// Using range() for numeric iteration
for int i in range(0, 10) {
print("Iteration: " + i.to_string())
}
// Explicit typing for clarity
auto collection = ["Bob", "Alice", "Eve"]
for string name in collection {
auto processed = create_message_to(name)
print(processed)
}
Ignoring Loop Variables
Use _ when you don't need the loop variable:
// Execute 10 times, don't care about index
for int _ in range(0, 10) {
doSomething()
}
Iterating Collections
// List iteration
auto nums = [10, 20, 30]
for int n in nums {
print(n.to_string())
}
auto myMap = {
"a": 1,
"b": 2,
"c": 3
}
// Map iteration on keys
for key in myMap.keys() {
print(key)
}
// Map iteration on vals
for value in myMap.keys() {
print(value)
}
auto mySet = {"a", "b", "c"}
for char in mySet {
print(char.to_string())
}
While Loops
Standard while loops with boolean conditions:
auto count = 0
while count < 10 {
print(count.to_string())
count++
}
// With type inference for locals
while condition {
auto currentTime = getCurrentTime()
if currentTime > threshold {
break
}
}
Break and Continue
Control loop execution:
// Break exits the loop
for int i in range(0, 100) {
if i > 10 {
break
}
print(i.to_string())
}
// Continue skips to next iteration
for int i in range(0, 10) {
if i % 2 == 0 {
continue // skip even numbers
}
print(i.to_string())
}
Match Statements
Pattern matching with guards and destructuring:
Basic Matching
match value {
1 {
print("one")
}
2 {
print("two")
}
_ {
print("other") // wildcard pattern
}
}
This is equivalent to:
if value == 1 {
print("one")
} else if value == 2 {
print("two")
} else {
print("other")
}
Matching optional
func findEven(list<int> xs) returns optional<int> {
for x in xs {
if x % 2 == 0 {
return some(x)
}
}
return none
}
auto maybeEven = findEven([1, 3, 4, 7])
match maybeEven {
some(value) {
print("Found even: " + value.to_string())
}
none {
print("No even number found")
}
}
Matching result
func divide(int a, int b) returns result<int, string> {
if b == 0 {
return err("division by zero")
}
return ok(a / b)
}
auto result = divide(10, 2)
match result {
ok(value) {
print("result: " + value.to_string())
}
err(error) {
print("Error: " + error)
}
}
Pattern Matching with Guards
Guards add conditional logic to patterns:
match value {
some(v) if v > 10 {
print("large: " + v.to_string())
}
some(v) if v > 0 {
print("small positive: " + v.to_string())
}
some(v) {
print("non-positive: " + v.to_string())
}
none {
print("no value")
}
}
Ignoring Values in Patterns
Use _ to ignore parts of patterns you don't need:
// Ignore the wrapped value
match maybeValue {
some(_) {
print("Got a value") // don't care what it is
}
none {
print("Got nothing")
}
}
// Ignore error details
match result {
ok(value) {
print("Success: " + value.to_string())
}
err(_) {
print("some error occurred") // don't care about details
}
}
Matching Enums
enum Shape {
Circle(float radius)
Rectangle(float width, float height)
Square(float size)
}
auto myShape = Circle.new(5.0)
match myShape {
Circle(r) {
print("Circle with radius: " + r.to_string())
}
Rectangle(w, h) {
print("Rectangle: " + w.to_string() + "x" + h.to_string())
}
Square(s) {
print("Square with size: " + s.to_string())
}
}
// Ignoring enum data
match shape {
Circle(_) {
print("It's a circle") // radius ignored
}
Rectangle(width, _) {
print("Rectangle with width: " + width.to_string()) // height ignored
}
Square(size) {
print("Square with size: " + size.to_string())
}
}
Wildcard Pattern
The _ pattern matches anything:
match status {
0 { print("success") }
1 { print("warning") }
2 { print("error") }
_ { print("unknown status") } // catch-all
}
Exhaustive Matching
Mux requires that all possible cases are handled in a match statement. If you miss a case, the compiler will give an error:
match value {
1 { print("one") }
2 { print("two") }
// Missing wildcard or other cases will cause a compile error!
}
Match as Switch Statement
Match statements can be used as switch statements for any type, not just enums:
// Match on int literals (like a switch)
auto status = 200
match status {
200 { print("OK") }
404 { print("Not Found") }
500 { print("Server Error") }
_ { print("Unknown status") }
}
// Match on string literals
auto command = "start"
match command {
"start" { print("Starting...") }
"stop" { print("Stopping...") }
"restart" { print("Restarting...") }
_ { print("Unknown command") }
}
// Match on bool values
auto flag = true
match flag {
true { print("Enabled") }
false { print("Disabled") }
}
// Match on char literals
auto letter = 'a'
match letter {
'a' { print("Alpha") }
'b' { print("Bravo") }
_ { print("Other") }
}
Variable Binding in Switch Patterns
Capture matched values in variables:
auto value = 42
match value {
1 { print("one") }
captured { print("got: " + captured.to_string()) }
_ { print("shouldn't reach here") }
}
// With strings
auto name = "world"
match name {
"admin" { print("Hello, admin!") }
n { print("Hello, " + n) }
}
Constants in Switch Patterns
Use constants as match patterns:
const int ADMIN = 1
const int MODERATOR = 2
auto level = 1
match level {
ADMIN { print("admin") }
MODERATOR { print("moderator") }
_ { print("user") }
}
List Literal Matching
Match on list structure:
auto nums = [1, 2, 3]
match nums {
[] { print("empty") }
[1] { print("single: 1") }
[1, 2] { print("two: 1, 2") }
[1, 2, 3] { print("three: 1, 2, 3") }
[first, ..rest] { print("has elements") }
_ { print("weird list") }
}
Switch with Guards
Add conditions to switch cases:
auto score = 85
match score {
n if n >= 90 { print("A") }
n if n >= 80 { print("B") }
n if n >= 70 { print("C") }
n if n >= 60 { print("D") }
_ { print("F") }
}
Return Statement
Exit a function early:
func findFirst(list<int> items, int target) returns optional<int> {
for i in range(0, items.size()) {
if items[i] == target {
return some(i) // early return
}
}
return none
}
func validate(int value) returns result<int, string> {
if value < 0 {
return err("value must be positive")
}
if value > 100 {
return err("value too large")
}
return ok(value)
}
Best Practices
- Use
matchfor result and optional - More expressive than if-else chains - Prefer pattern matching with guards - Cleaner than nested if statements
- Use
_for unused values - Makes intent explicit - Early returns for error conditions - Reduces nesting
- Use
range()for numeric loops - Idiomatic Mux - Break and continue judiciously - Can make code harder to follow if overused
See Also
- Error Handling - Using result and optional with match
- Enums - Pattern matching with tagged unions
- Functions - Return statements and early exits
- Variables - Type inference with
auto