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:
my int $logged_in = 0;
unless ($logged_in) {
say("Please log in");
}
# 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++;
}
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
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);
}
}
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");
}
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";