Control Flow

Control flow statements allow you to control the execution path of your program based on conditions and iterations.

Overview

Charl provides three main control flow constructs:

if/else

Conditional branching based on boolean expressions

while

Repeat code while a condition is true

match

Pattern matching for complex conditionals

if/else Statements

The if statement executes a block of code only if a condition is true.

Basic if Statement

let x = 10

if x > 5 {
    print("x is greater than 5")
}

// With multiple statements
if x > 0 {
    print("x is positive")
    let doubled = x * 2
    print("doubled: " + str(doubled))
}

if/else Statement

let age = 18

if age >= 18 {
    print("You are an adult")
} else {
    print("You are a minor")
}

// With calculations
let temperature = 25.0
if temperature > 30.0 {
    print("It's hot outside")
} else {
    print("It's not too hot")
}

else if Chains

let score = 85

if score >= 90 {
    print("Grade: A")
} else if score >= 80 {
    print("Grade: B")
} else if score >= 70 {
    print("Grade: C")
} else if score >= 60 {
    print("Grade: D")
} else {
    print("Grade: F")
}

// Multiple conditions in else if
let x = 15
if x < 0 {
    print("Negative")
} else if x >= 0 && x < 10 {
    print("Small positive")
} else if x >= 10 && x < 100 {
    print("Medium positive")
} else {
    print("Large positive")
}

Nested if Statements

let is_weekend = true
let has_homework = false

if is_weekend {
    if has_homework {
        print("Do homework first, then relax")
    } else {
        print("Enjoy your free weekend!")
    }
} else {
    print("It's a weekday, time for school")
}

// Complex nesting
let age = 25
let has_license = true
let has_car = false

if age >= 18 {
    if has_license {
        if has_car {
            print("You can drive your own car")
        } else {
            print("You can drive, but need to rent a car")
        }
    } else {
        print("You need to get a license first")
    }
} else {
    print("You're too young to drive")
}

Best Practice: Avoid deep nesting. Consider using early returns or breaking logic into separate functions.

while Loops

The while loop repeats a block of code as long as a condition remains true.

Basic while Loop

// Count from 0 to 4
let i = 0
while i < 5 {
    print("Count: " + str(i))
    let i = i + 1  // Shadowing creates new variable
}

// Sum numbers 1 to 10
let sum = 0
let n = 1
while n <= 10 {
    let sum = sum + n
    let n = n + 1
}
print("Sum: " + str(sum))  // 55

Note: Since variables are immutable, you must use shadowing (redeclaring with let) to update loop counters.

Condition-Based Loops

// Loop until condition met
let x = 1.0
while x < 100.0 {
    print("x: " + str(x))
    let x = x * 2.0  // Double each iteration
}

// Search in array
let numbers = [1, 3, 5, 7, 9, 11]
let target = 7
let found = false
let index = 0

while index < len(numbers) && !found {
    if numbers[index] == target {
        print("Found at index: " + str(index))
        let found = true
    }
    let index = index + 1
}

Infinite Loops with Break Condition

// Training loop example
let epoch = 0
let max_epochs = 1000
let loss = 1.0
let min_loss = 0.01

while epoch < max_epochs {
    // Simulate training step
    let loss = loss * 0.95  // Loss decreases

    print("Epoch " + str(epoch) + ", Loss: " + str(loss))

    // Check convergence
    if loss < min_loss {
        print("Converged!")
        // In practice, you'd break here
        // Charl doesn't have break, so use condition
        let epoch = max_epochs  // Force loop to end
    }

    let epoch = epoch + 1
}

Warning: Make sure your while loop condition eventually becomes false. Infinite loops will hang your program.

match Expressions

The match expression provides pattern matching for elegant conditional logic.

Basic Pattern Matching

let number = 2

let result = match number {
    1 => "one"
    2 => "two"
    3 => "three"
    _ => "other"  // Default case (wildcard)
}
print(result)  // "two"

// With different types
let status_code = 200
let message = match status_code {
    200 => "OK"
    404 => "Not Found"
    500 => "Internal Server Error"
    _ => "Unknown Status"
}

Matching with Expressions

let x = 42

let category = match x {
    0 => "zero"
    1 => "one"
    _ => if x < 0 {
        "negative"
    } else {
        "positive"
    }
}

// Multiple statements in match arms
let grade = 85
match grade {
    _ => if grade >= 90 {
        print("Excellent!")
        print("Grade: A")
    } else if grade >= 80 {
        print("Good job!")
        print("Grade: B")
    } else {
        print("Keep trying!")
        print("Grade: C or below")
    }
}

Practical Match Examples

// Day of week
let day_num = 3
let day_name = match day_num {
    1 => "Monday"
    2 => "Tuesday"
    3 => "Wednesday"
    4 => "Thursday"
    5 => "Friday"
    6 => "Saturday"
    7 => "Sunday"
    _ => "Invalid day"
}

// Activation function selection
let activation = "relu"
let output = match activation {
    "relu" => if x > 0.0 { x } else { 0.0 }
    "sigmoid" => 1.0 / (1.0 + tensor_exp(tensor([-x])))
    "tanh" => tensor_tanh(tensor([x]))
    _ => x  // Linear (identity)
}

Exhaustiveness: Always include a wildcard _ pattern to handle unexpected values.

Combining Control Flow

You can combine different control flow constructs to create complex logic.

if inside while

// Process array elements conditionally
let numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
let i = 0
let even_sum = 0
let odd_sum = 0

while i < len(numbers) {
    if numbers[i] % 2 == 0 {
        let even_sum = even_sum + numbers[i]
    } else {
        let odd_sum = odd_sum + numbers[i]
    }
    let i = i + 1
}

print("Even sum: " + str(even_sum))  // 30
print("Odd sum: " + str(odd_sum))    // 25

Nested Loops

// Matrix-like iteration
let rows = 3
let cols = 3
let i = 0

while i < rows {
    let j = 0
    while j < cols {
        let value = i * cols + j
        print("(" + str(i) + "," + str(j) + ") = " + str(value))
        let j = j + 1
    }
    let i = i + 1
}

// Multiplication table
let i = 1
while i <= 5 {
    let j = 1
    while j <= 5 {
        let product = i * j
        print(str(i) + " × " + str(j) + " = " + str(product))
        let j = j + 1
    }
    let i = i + 1
}

match inside Loops

// Process commands
let commands = ["start", "process", "stop", "restart"]
let i = 0

while i < len(commands) {
    let cmd = commands[i]
    match cmd {
        "start" => print("Starting system...")
        "stop" => print("Stopping system...")
        "restart" => print("Restarting system...")
        "process" => print("Processing data...")
        _ => print("Unknown command: " + cmd)
    }
    let i = i + 1
}

Complete Examples

Example 1: Factorial Calculation

// Calculate factorial using while loop
let n = 5
let result = 1
let i = 1

while i <= n {
    let result = result * i
    let i = i + 1
}

print("Factorial of " + str(n) + " is " + str(result))  // 120

Example 2: Fibonacci Sequence

// Generate first 10 Fibonacci numbers
let n = 10
let a = 0
let b = 1
let count = 0

print("Fibonacci sequence:")
while count < n {
    print(str(a))
    let temp = a + b
    let a = b
    let b = temp
    let count = count + 1
}

Example 3: Simple Training Loop

// Simplified gradient descent
let learning_rate = 0.1
let x = 10.0  // Starting point
let target = 5.0
let max_iterations = 100
let tolerance = 0.001
let iteration = 0

while iteration < max_iterations {
    // Calculate error (loss)
    let error = x - target

    // Check if converged
    if error < tolerance && error > -tolerance {
        print("Converged at iteration " + str(iteration))
        let iteration = max_iterations  // Exit loop
    } else {
        // Update x (gradient descent step)
        let x = x - learning_rate * error

        if iteration % 10 == 0 {
            print("Iteration " + str(iteration) + ": x = " + str(x))
        }

        let iteration = iteration + 1
    }
}

print("Final value: " + str(x))

Example 4: Data Validation

// Validate dataset
let data = [1.0, 2.0, 3.0, -1.0, 5.0]
let i = 0
let valid = true
let errors = 0

while i < len(data) {
    let value = data[i]

    if value < 0.0 {
        print("Error at index " + str(i) + ": negative value")
        let errors = errors + 1
        let valid = false
    } else if value > 100.0 {
        print("Error at index " + str(i) + ": value too large")
        let errors = errors + 1
        let valid = false
    }

    let i = i + 1
}

if valid {
    print("All data valid!")
} else {
    print("Found " + str(errors) + " errors")
}

Best Practices

DO:

  • Keep conditions simple and readable
  • Use meaningful variable names in loop counters
  • Always ensure while loop conditions will eventually become false
  • Use match for clean multi-way branches
  • Add comments for complex control flow logic
  • Include wildcard patterns (_) in match expressions

DON'T:

  • Nest if statements more than 2-3 levels deep
  • Create infinite loops without clear exit conditions
  • Use complex boolean expressions without parentheses
  • Forget to update loop counters (using shadowing)
  • Use long else if chains when match would be clearer

Next Steps