Control Flow

Conditionals, loops, and exception handling.

Conditionals

If / Elsif / Else

my int $x = 10;

if ($x > 10) {
    say("Greater than 10");
} elsif ($x == 10) {
    say("Equal to 10");
} else {
    say("Less than 10");
}

Unless

unless is the opposite of if — it executes when the condition is false:

my int $logged_in = 0;

unless ($logged_in) {
    say("Please log in");
}

# With else (no elsif allowed with unless)
unless ($logged_in) {
    say("Please log in");
} else {
    say("Welcome back");
}

# Equivalent to:
if (!$logged_in) {
    say("Please log in");
}

Ternary Operator

my int $age = 20;
my str $status = $age >= 18 ? "adult" : "minor";
say($status);  # "adult"

Loops

While Loop

my int $i = 0;
while ($i < 5) {
    say($i);
    $i++;
}

Until Loop

until is the opposite of while — it loops while the condition is false:

my int $count = 0;
until ($count >= 5) {
    say($count);
    $count++;
}
# Equivalent to: while ($count < 5) { ... }

Do-While Loop

my int $i = 0;
do {
    say($i);
    $i++;
} while ($i < 5);

For Loop

for (my int $i = 0; $i < 5; $i++) {
    say("i = " . $i);
}

Foreach Loop

Iterate over arrays:

my array @fruits = ["apple", "banana", "cherry"];

# With type declaration
foreach my str $fruit (@fruits) {
    say($fruit);
}

# Without type (uses existing variable)
my str $item;
foreach $item (@fruits) {
    say($item);
}

# "for" works like "foreach" with arrays
for my str $fruit (@fruits) {
    say($fruit);
}

Increment/Decrement

my int $x = 5;

$x++;        # Post-increment: returns 5, then x becomes 6
++$x;        # Pre-increment: x becomes 7, returns 7
$x--;        # Post-decrement: returns 7, then x becomes 6
--$x;        # Pre-decrement: x becomes 5, returns 5

# Often used in loops
my int $i = 0;
while ($i < 10) {
    say($i++);  # Print then increment
}

Loop Control

for (my int $i = 0; $i < 10; $i++) {
    if ($i == 3) {
        next;      # Skip to next iteration
    }
    if ($i == 7) {
        last;      # Exit loop
    }
    say($i);
}
# Output: 0, 1, 2, 4, 5, 6

# redo - restart current iteration without re-checking condition
my int $attempts = 0;
while ($attempts < 3) {
    $attempts++;
    my str $input = readline();
    if ($input eq "") {
        say("Input required");
        redo;    # Restart iteration (don't re-check or advance)
    }
}

Labeled Loops

Labels allow breaking out of nested loops:

OUTER: for (my int $i = 0; $i < 5; $i++) {
    INNER: for (my int $j = 0; $j < 5; $j++) {
        if ($j == 2) {
            next INNER;   # Skip to next inner iteration
        }
        if ($i == 3) {
            last OUTER;   # Exit both loops
        }
        say("i=" . $i . " j=" . $j);
    }
}

Functional Array Operations

Strada supports Perl-style map, grep, and sort for powerful array transformations. Use $_ for the current element.

Map (Transform)

my array @nums = (1, 2, 3, 4, 5);

# Transform each element
my array @doubled = map { $_ * 2 } @nums;
# Result: (2, 4, 6, 8, 10)

Map to Hash (Perl Idiom)

Create lookup hashes using the fat arrow (=>):

my array @fruits = ("apple", "banana", "cherry");

# The classic Perl idiom - works in Strada!
my hash %lookup = map { $_ => 1 } @fruits;

# Fast O(1) membership testing
if (exists($lookup{"apple"})) {
    say("Found apple!");
}

Grep (Filter)

my array @nums = (1, 2, 3, 4, 5, 6);

# Keep only even numbers
my array @evens = grep { $_ % 2 == 0 } @nums;
# Result: (2, 4, 6)

Sort

my array @nums = (5, 2, 8, 1, 9);

# Numeric sort (ascending) - use $a, $b with spaceship
my array @asc = sort { $a <=> $b } @nums;

# Descending
my array @desc = sort { $b <=> $a } @nums;

Chaining Operations

# Filter, transform, and sort in one line
my array @result = sort { $a <=> $b } map { $_ * 10 } grep { $_ > 3 } @data;
See Also: Built-in Functions Reference for more examples.

Exception Handling

Try / Catch / Throw

func divide(int $a, int $b) int {
    if ($b == 0) {
        throw "Division by zero!";
    }
    return $a / $b;
}

func main() int {
    try {
        my int $result = divide(10, 0);
        say("Result: " . $result);
    } catch ($e) {
        say("Error: " . $e);
    }
    say("Program continues...");
    return 0;
}
Exception Values The throw statement can throw any value (string, number, etc.). The catch block receives that value in its parameter.

Nested Try/Catch

try {
    try {
        throw "Inner error";
    } catch ($e) {
        say("Caught inner: " . $e);
        throw "Re-throwing";  # Re-throw or throw new
    }
} catch ($e) {
    say("Caught outer: " . $e);
}

Goto and Labels

For exceptional control flow (use sparingly):

func main() int {
    my int $i = 0;

start:
    say($i);
    $i++;
    if ($i < 5) {
        goto start;
    }

    say("Done");
    return 0;
}
Use Sparingly goto can make code hard to follow. Prefer structured control flow (loops, functions) in most cases. It's occasionally useful for cleanup code or state machines.

Pattern Matching

Use regex in conditionals:

my str $input = "hello123";

if ($input =~ /[0-9]+/) {
    say("Contains numbers");
}

if ($input !~ /^[0-9]+$/) {
    say("Not purely numeric");
}

# Case-insensitive match
if ($input =~ /HELLO/i) {
    say("Found hello (case-insensitive)");
}

Switch Statement

Use switch for multi-way branching:

my int $day = 3;

switch ($day) {
    case 1 {
        say("Monday");
    }
    case 2 {
        say("Tuesday");
    }
    case 3 {
        say("Wednesday");
    }
    default {
        say("Other day");
    }
}
No Fall-Through Unlike C/Java, each case is self-contained with braces. There's no fall-through behavior and no break statement needed.

Switch with Strings

my str $color = "red";

switch ($color) {
    case "red" {
        say("Stop");
    }
    case "yellow" {
        say("Caution");
    }
    case "green" {
        say("Go");
    }
    default {
        say("Unknown signal");
    }
}

Alternative: Hash Dispatch

For dynamic dispatch or function tables, hashes work well:

my hash %day_names = {
    "Mon" => "Monday",
    "Tue" => "Tuesday",
    "Wed" => "Wednesday"
};

my str $day = "Mon";
if (exists(%day_names, $day)) {
    say($day_names{$day});
} else {
    say("Unknown day");
}

Statement Modifiers

Perl-style postfix modifiers let you write concise one-liners:

# Postfix if/unless
say("hello") if $verbose;
say("warning") unless $quiet;

# Postfix while/until
$i = $i + 1 while $i < 10;
$i = $i + 1 until $i >= 10;

# Works with return, last, next, redo
return 0 if $error;
return $val unless $invalid;
last if $done;
next unless $valid;
Modifier Forms EXPR if COND; is equivalent to if (COND) { EXPR; }. EXPR unless COND; is equivalent to if (!COND) { EXPR; }. EXPR while COND; is equivalent to while (COND) { EXPR; }. EXPR until COND; is equivalent to while (!COND) { EXPR; }.

Short-Circuit Evaluation

# && and || short-circuit
my int $x = 0;

# Second expression not evaluated if first is false
$x && say("x is true");

# Second expression not evaluated if first is true
$x || say("x is false");

# Use for default values
my str $name = "";
my str $display = $name || "Anonymous";