Control flow¶
This page explains branching and looping constructs in Incan.
Branching with if¶
def classify(n: int) -> str:
if n < 0:
return "negative"
elif n == 0:
return "zero"
else:
return "positive"
Use ordinary if when the condition is a boolean expression and both the true/false shape of the branch matters.
Pattern-oriented branching with if let¶
Use if let when you want to try one pattern match and do something only on success.
def print_primary_email(user: Option[User]) -> None:
if let Some(u) = user:
println(u.email)
This is the concise form of “match one successful shape, otherwise do nothing.” It is most useful with Option, Result, and enum payloads.
def log_port(raw: str) -> None:
if let Ok(port) = parse_port(raw):
println(f"listening on {port}")
Prefer if let when:
- exactly one successful pattern matters;
- the non-match path should do nothing;
- the code reads more naturally as opportunistic extraction than as full branching.
Use match instead when the non-match path matters, when you need more than one arm, or when you want exhaustiveness to stay explicit.
match parse_port(raw):
case Ok(port): println(f"listening on {port}")
case Err(e): println(f"invalid port: {e}")
if let bindings exist only inside the body. In v1, if let is intentionally single-arm only and does not accept elif or else.
Pattern matching with match¶
Use match to branch on enum values like Result and Option.
def main() -> None:
result = parse_port("8080")
match result:
case Ok(port): println(f"port={port}")
case Err(e): println(f"error: {e}")
Use match when:
- both success and failure paths matter;
- more than one variant needs its own behavior;
- you want the full branching structure to stay visible.
Looping while a pattern keeps matching with while let¶
Use while let when a loop should continue only while one pattern keeps matching.
async def drain(rx: Receiver[str]) -> None:
while let Some(msg) = await rx.recv():
println(f"Got: {msg}")
This replaces the more repetitive shape:
while True:
match await rx.recv():
case Some(msg): println(f"Got: {msg}")
case None: break
Prefer while let when:
- each iteration destructures the same success case;
- the loop naturally ends on the first non-match;
while Trueplusmatchplusbreakadds noise rather than meaning.
Like if let, names bound by the pattern exist only inside the successful body of that iteration.
Looping with for¶
Incan supports Python-like for loops:
def main() -> None:
items = ["Alice", "Bob", "Cara"]
for name in items:
println(name)
Break early when needed:
for name in items:
if name == "Bob":
break
Looping with while¶
Use while when the loop condition should be checked before each iteration:
def countdown(start: int) -> None:
mut current = start
while current > 0:
println(current)
current -= 1
Looping with loop¶
Use loop: for explicit infinite loops and for loops that produce a value with break <expr>.
def find_value(flag: bool) -> int:
return loop:
if flag:
break 42
break 7
break <expr> is only valid for loop:. Plain break remains valid for for, while, and loop:.
See also¶
- Book chapter: 4. Control flow
- Enums and
match: Enums - Error-driven control flow (
Result/Option): Error Handling