Control Flow¶
Desi provides familiar control flow constructs with Python-inspired syntax and powerful pattern matching.
Conditional Statements¶
if / elif / else¶
Nested Conditions¶
if condition1:
print("Outer true")
if condition2:
print("Inner true")
else:
print("Inner false")
else:
print("Outer false")
Condition Expressions¶
Conditions must evaluate to bool:
Chained Comparisons¶
Python-style chained comparisons:
let y: int = 50
if 0 < y < 100: # Same as: y > 0 and y < 100
print("y is between 0 and 100")
if 1 <= y <= 100: # Inclusive range
print("y is in range 1-100")
Loops¶
while Loop¶
let mut count: int = 0
while count < 5:
print(count)
count := count + 1
print("Done") # Prints: 0 1 2 3 4 Done
for...in Loop¶
Iterate over collections:
enumerate()¶
Get index and value pairs:
let items: list[str] = ["apple", "banana", "cherry"]
for i: int, item: str in enumerate(items):
print(i) # 0, 1, 2
print(item) # apple, banana, cherry
zip()¶
Iterate over multiple collections in parallel:
let names: list[str] = ["Alice", "Bob"]
let scores: list[int] = [95, 87]
for name: str, score: int in zip(names, scores):
print(name)
print(score)
One-Line Form¶
For simple statements:
break and continue¶
break leaves the loop. continue skips the rest of the current iteration and
starts the next one. Both work in while and for, and both act on the
innermost loop containing them.
def main() -> int:
let items: list[int] = [10, 20, 30, 40]
# break: stop at the first match
let mut found: int = 0
for x in items:
if x == 30:
found := x
break
print(str(found)) # 30
# continue: skip one value, keep going
let mut total: int = 0
for y in items:
if y == 20:
continue
total := total + y
print(str(total)) # 80
return 0
In nested loops, a jump only affects the loop it is written in. To leave both, set a flag in the inner loop and test it in the outer one:
def main() -> int:
let mut done: bool = false
let mut hit: int = 0
for a in [1, 2, 3]:
for b in [10, 20, 30]:
if a * b == 40:
hit := a * b
done := true
break
if done:
break
print(str(hit)) # 40
return 0
Both statements run the cleanup for every scope they leave. Anything the loop
body allocated is released, and a using block is closed, before control moves
on — leaving early never skips a destructor:
class Resource:
pub def __close__(self) -> none:
print("closed")
return
def main() -> int:
for i in range(3):
using r = Resource():
if i == 1:
break # prints "closed", then leaves the loop
print("kept " + str(i))
return 0
Using either outside a loop is a compile error, not a silent no-op.
Pattern Matching¶
The match expression provides powerful pattern matching, especially useful with enums.
Basic Match¶
enum Color:
Red: none
Green: none
Blue: none
def color_name(c: Color) -> str:
match c:
Color.Red(): "Red"
Color.Green(): "Green"
Color.Blue(): "Blue"
Match with Bindings¶
Extract values from enum variants:
A variant is written Name: PayloadType, with none for no payload:
enum Outcome:
Ok: int
Err: str
def handle_result(r: Outcome) -> str:
return match r:
Outcome.Ok(v): f"Success: {v}"
Outcome.Err(msg): f"Error: {msg}"
Wildcard Pattern¶
Use _ to match any value:
enum Status:
Idle: none
Running: none
Paused: none
Stopped: none
def is_active(s: Status) -> bool:
match s:
Status.Running(): true
Status.Paused(): true
_: false # Matches Idle and Stopped
Match as Expression¶
Match expressions return a value:
Option Pattern¶
Result Pattern¶
Each arm is a single expression. When a branch needs statements, call a function from the arm rather than opening a block:
def report(msg: str) -> int:
print(f"Error: {msg}")
return -1
def handle(result: Result<int, str>) -> int:
return match result:
Result.Ok(value): value
Result.Err(msg): report(msg)
Multiple Arms¶
enum Day:
Monday: none
Tuesday: none
Wednesday: none
Thursday: none
Friday: none
Saturday: none
Sunday: none
def is_weekend(day: Day) -> bool:
match day:
Day.Saturday(): true
Day.Sunday(): true
_: false
Exhaustiveness Checking¶
The compiler ensures all enum variants are handled:
enum Color:
Red: none
Green: none
Blue: none
# ❌ Error: non-exhaustive match
def color_code(c: Color) -> int:
match c:
Color.Red(): 1
Color.Green(): 2
# Missing Color.Blue()!
# ✅ Correct: all variants handled
def color_code(c: Color) -> int:
match c:
Color.Red(): 1
Color.Green(): 2
Color.Blue(): 3
Or use wildcard to catch remaining:
# ✅ Correct: wildcard catches Blue
def is_red(c: Color) -> bool:
match c:
Color.Red(): true
_: false
Boolean Operators¶
Logical Operators¶
let a: bool = true
let b: bool = false
let and_result: bool = a and b # false
let or_result: bool = a or b # true
let not_result: bool = not a # false
Short-Circuit Evaluation¶
and and or use short-circuit evaluation:
# right side not evaluated if left is false
if false and expensive_check():
pass
# right side not evaluated if left is true
if true or expensive_check():
pass
Comparison Operators¶
| Operator | Description |
|---|---|
== |
Equal |
!= |
Not equal |
< |
Less than |
> |
Greater than |
<= |
Less than or equal |
>= |
Greater than or equal |
in |
Membership test |
Membership Testing¶
let nums: list[int] = [1, 2, 3, 4, 5]
if 3 in nums:
print("Found!")
let dict: dict[str, int] = {"a": 1, "b": 2}
if "a" in dict:
print("Key exists!")
Best Practices¶
✅ Do¶
- Use match for enums: Safer than if/elif chains
- Prefer for...in over while when possible: Clearer intent
- Use enumerate() for indexed iteration: Avoids manual indexing
- Handle all enum variants: Use exhaustive matching
❌ Don't¶
- Don't use while(true) without break: Prefer bounded loops
- Avoid deeply nested conditions: Extract to functions
- Don't ignore match warnings: Compiler catches missing cases
Common Patterns¶
Guard Clauses¶
def process(value: Option<int>) -> int:
if value == Option.Nothing:
return 0 # Early return
# Continue with valid value
match value:
Option.Some(n): n * 2
_: 0 # Unreachable but satisfies compiler
Loop with Index¶
let items: list[str] = ["a", "b", "c"]
for i: int, item: str in enumerate(items):
print(f"Item {i}: {item}")
Collecting Results¶
let numbers: list[int] = [1, 2, 3, 4, 5]
let mut doubled: list[int] = []
for n in numbers:
doubled.append(n * 2)
Early Exit Pattern¶
def find_first(items: list[int], target: int) -> Option<int>:
for i: int, item: int in enumerate(items):
if item == target:
return Option.Some(i)
return Option.Nothing
See Also¶
- Functions - Function definitions
- Error Handling - Option and Result types
- Types - Boolean and comparison types