Skip to content
Pre-Release: Fe is under active development. This documentation covers the upcoming release. Follow progress on GitHub

Control Flow

Control flow constructs determine the order in which code executes. Fe provides conditionals, pattern matching, and loops, all designed as expressions that can return values.

Use if to execute code based on a condition:

if balance > 0 {
process_withdrawal()
}

Add an else branch for when the condition is false:

if balance >= amount {
withdraw(amount)
} else {
reject_transaction()
}

Chain multiple conditions with else if:

let grade = if score >= 90 {
"A"
} else if score >= 80 {
"B"
} else if score >= 70 {
"C"
} else {
"F"
}

In Fe, if is an expression that returns a value. Both branches must return the same type:

let max = if a > b { a } else { b }
let status = if is_active {
"active"
} else {
"inactive"
}

This is useful for concise conditional assignment:

let fee = if is_premium { 0 } else { calculate_fee(amount) }

The match expression provides powerful pattern matching:

match value {
0 => handle_zero()
1 => handle_one()
_ => handle_other()
}

Like if, match is an expression that returns a value:

let description = match count {
0 => "none"
1 => "one"
2 => "two"
_ => "many"
}

Match on enum variants to handle different cases:

enum Status {
Pending,
Approved,
Rejected(String<64>),
}
let status = Status::Pending
let message: String<64> = match status {
Status::Pending => "Awaiting review"
Status::Approved => "Request approved"
Status::Rejected(reason) => reason // Extract the reason
}

Use patterns to destructure and bind values:

let location = match point {
(0, 0) => "origin"
(0, _) => "on y-axis"
(_, 0) => "on x-axis"
(_, _) => "somewhere else"
}

Match on struct fields:

match user {
User { active: true, role } => process_active(role)
User { active: false, .. } => handle_inactive()
}

Use _ to match any value you don’t need:

match result {
Result::Ok(value) => use_value(value)
Result::Err(_) => handle_error() // Ignore the specific error
}

Match expressions must be exhaustive. Every possible value must be handled. The wildcard _ is often used as a catch-all:

let day_name = match day {
1 => "Monday"
2 => "Tuesday"
3 => "Wednesday"
4 => "Thursday"
5 => "Friday"
6 => "Saturday"
7 => "Sunday"
_ => "Invalid day" // Handle all other values
}

Use for to iterate over a collection:

for item in items {
process(item)
}

Destructure elements while iterating:

for (index, value) in indexed_items {
store_at(index, value)
}
for User { name, balance } in users {
if balance > 0 {
credit(name, balance)
}
}

Use while for condition-based loops:

let mut count: u256 = 5
while count > 0 {
process_next()
count = count - 1
}

A common pattern for indefinite loops:

while true {
if should_stop() {
break
}
do_work()
}

Use break to exit a loop early:

for item in items {
if item.is_target() {
found = item
break // Exit the loop
}
}

Use continue to skip to the next iteration:

for item in items {
if item.should_skip() {
continue // Skip this item
}
process(item)
}
let mut sum: u256 = 0
for value in values {
// Skip negative values
if value < 0 {
continue
}
// Stop if we exceed the limit
if sum + value > limit {
break
}
sum = sum + value
}

Use return to exit a function early:

fn find_user(id: u256) -> Option<User> {
if id == 0 {
return Option::None // Early return for invalid ID
}
// ... lookup logic ...
Option::Some(user) // Implicit return
}

Return a specific value from anywhere in the function:

fn calculate_discount(amount: u256, is_member: bool) -> u256 {
if amount < 100 {
return 0 // No discount for small amounts
}
if is_member {
return amount / 10 // 10% for members
}
amount / 20 // 5% for non-members (implicit return)
}

Fe functions return the value of their last expression implicitly. Use explicit return for:

  • Early exits from the function
  • Multiple exit points
  • Clarity in complex functions
// Implicit return - last expression is the return value
fn double(x: u256) -> u256 {
x * 2
}
// Explicit return - needed for early exit
fn safe_divide(a: u256, b: u256) -> Option<u256> {
if b == 0 {
return Option::None
}
Option::Some(a / b)
}
ConstructSyntaxDescription
ifif cond { }Conditional execution
if-elseif cond { } else { }Two-way branch
else ifif c1 { } else if c2 { }Multi-way branch
matchmatch val { pat => expr }Pattern matching
forfor pat in iter { }Iteration over collection
whilewhile cond { }Condition-based loop
breakbreakExit loop early
continuecontinueSkip to next iteration
returnreturn or return exprExit function early