Iterating in Perl
Perl offers while, until, a C-style for, and foreach (which can also be written for) for iteration. foreach is idiomatic for stepping through the elements of a list, defaulting to the topic variable $_ when no named loop variable is given, while while/until are driven purely by a boolean condition rather than a list.
Cricket analogy: Bowling all six deliveries of an over is like Perl's foreach looping over a fixed list, while a bowler continuing to bowl until the batting side is dismissed resembles a while loop running until a condition changes.
while, until, and C-style for
while(COND) { ... } repeats its body as long as COND is true, testing before each pass; until(COND) is its logical inverse. The C-style for(init; cond; incr) { ... } gives explicit control over an initializer, a test, and a step expression, evaluated in that order each pass. do { ... } while/until differs from all of these by testing after the first execution, guaranteeing the body runs at least once.
Cricket analogy: A run chase can turn into an infinite ordeal if the required-rate calculation never updates the loop condition, just as a Perl while ($overs_left) {...} loop spins forever if nothing inside the block ever decrements $overs_left.
# while loop reading input until EOF
my @lines;
while (my $line = <STDIN>) {
chomp $line;
push @lines, $line;
}
# C-style for loop counting
for (my $i = 1; $i <= 5; $i++) {
print "Iteration $i\n";
}
# foreach with labeled loop and next/last
OUTER: foreach my $row (1..3) {
foreach my $col (1..3) {
next OUTER if $col == 2 && $row == 2;
print "row=$row col=$col\n";
}
}foreach and Aliasing to $_
foreach my $item (@list) { ... } binds $item to each element of @list in turn. Crucially, $item is an alias to the real array element, not a copy — assigning to it inside the loop body mutates the underlying array. When no named variable is given, foreach uses the default topic variable $_, which many built-in functions also read implicitly.
Cricket analogy: When a scorer walks through foreach my $run (@ball_by_ball) and reassigns $run to correct a miscounted no-ball, that edit changes the actual @ball_by_ball array, because Perl's foreach variable is an alias to the real element, not a copy.
Perl's foreach loop variable is aliased to the actual array element, not a copy. Writing foreach my $n (@nums) { $n *= 2; } doubles every value in @nums itself. If you don't want to mutate the source array, copy explicitly first, e.g. foreach my $n (@nums) { my $doubled = $n * 2; ... }.
Loop Control: next, last, redo, and Labels
next skips the remainder of the current iteration's body and moves on, re-testing the loop's condition. last exits the enclosing loop entirely. redo re-executes the current iteration's body from the top without re-testing the condition or advancing to the next element. By default these affect only the innermost loop; a label like OUTER: placed before a loop lets next/last/redo target that outer loop explicitly from inside a nested one.
Cricket analogy: A bowler who overstepped calls for a redo of that delivery, it doesn't count and gets bowled again, just like Perl's redo restarting the current loop iteration without re-testing the condition or advancing to the next element.
redo re-runs the current loop body without re-testing the loop's condition or moving to the next element, so a redo that isn't eventually guarded by some changing state can loop forever, unlike next, which always advances the iteration first. Labeled loops (e.g., OUTER:) are the only way to target next/last/redo at an outer loop from inside a nested one.
- while loops run while a condition is true; until loops run while a condition is false — they're logical inverses.
- C-style for(init; cond; incr) loops give explicit control over initialization, testing, and stepping.
- foreach (or its alias for) iterates over a list, aliasing the loop variable directly to each element.
- do { ... } while/until guarantees the block runs at least once before the condition is tested.
- next skips to the next iteration; last exits the loop entirely; redo re-runs the current iteration without re-testing.
- Labeled loops (OUTER: ...) let next/last/redo target an outer loop from within a nested one.
- Modifying the foreach loop variable modifies the underlying array element unless you explicitly copy it first.
Practice what you learned
1. What is the key difference between while and until in Perl?
2. In foreach my $n (@nums) { $n *= 2; }, what happens to @nums after the loop?
3. What does do { ... } while (COND); guarantee that a plain while (COND) { ... } does not?
4. What is the effect of redo inside a loop?
5. Why would you use a labeled loop like OUTER: foreach my $row (...) { foreach my $col (...) { next OUTER if ...; } }?
Was this page helpful?
You May Also Like
Conditionals in Perl
Learn how Perl evaluates truth and branches control flow using if, unless, elsif, and postfix conditional modifiers.
Subroutines in Perl
Understand how to define and call Perl subroutines, pass arguments via @_, return values, and use references for pass-by-reference semantics.
Context in Perl (Scalar vs List)
Learn how Perl's scalar and list context changes the meaning of operators and function calls, and how to control context explicitly.
Related Reading
Related Study Notes in Programming
Browse all study notesApache Spark Study Notes
Programming · 30 topics
ProgrammingApache Flink Study Notes
Programming · 30 topics
ProgrammingHadoop Study Notes
Programming · 30 topics
ProgrammingSnowflake Study Notes
Programming · 30 topics
ProgrammingApache Airflow Study Notes
Programming · 30 topics
Programmingdbt (Data Build Tool) Study Notes
Programming · 30 topics