Skip to content
VLSI Mentor

Perl Part I · Module 9 · Loops

last, next and redo

A loop that can only run to completion is a loop you have to write defensively. Perl's three loop-control keywords let the body decide instead: skip this item, stop entirely, or try this item again. The first two are everywhere in working code and are the reason a parsing loop can open with a stack of one-line guards. The third is rare, and it is worth a careful look rather than a mention, because it is the only one that does not move the loop forward — which makes an unguarded use of it a loop that never ends. There is also one behaviour here that is the exact opposite of what a C or SystemVerilog background predicts, and it concerns the part of a Perl loop most people do not know exists.

Foundation14 min readPerlPart IControl FlowLoops

Part I · Module 9 · Chapter 9.5 · last, next and redo

1. next and last

Azvya Education Pvt. Ltd.VLSI Mentor
nextlast.pl
use strict;
use warnings;

for my $n (1 .. 8) {
    next if $n % 2;        # skip odd
    last if $n > 6;        # stop past 6
    print "$n ";
}
print "\n";
Azvya Education Pvt. Ltd.VLSI Mentor
Captured output
2 4 6

Trace it, because the result is slightly more interesting than it looks:

  • 1, 3, 5, 7 — odd, so $n % 2 is 1, which is true, so next skipped them before anything printed.
  • 2, 4, 6 — even, passed the next, failed $n > 6, printed.
  • 8 — even, so it passed the next guard, then 8 > 6 was true and last ended the loop.

So 7 was skipped by next and 8 stopped the loop. The order of the two guards decides that: swap them and 7 would have ended it instead.

KeywordEffect
nextstop this pass, go to the next item
laststop the loop entirely
redostart this pass again, with the same item

All three work in for, foreach, while, until and a bare block. None of them works in a do { } while — that is Chapter 9.4's subject, and the error is fatal at run time.

The postfix form — next if COND; — is Chapter 8.3's statement modifier, and §5 there measured that this is the dominant real use of modifiers. A parsing loop opening with four next if guards is the single most common loop shape in Perl.

2. last Exits the Innermost Loop Only

Azvya Education Pvt. Ltd.VLSI Mentor
last-inner.pl
use strict;
use warnings;

for my $i (1 .. 3) {
    for my $j (1 .. 3) {
        last if $j == 2;
        print "$i$j ";
    }
}
print "\n";
Azvya Education Pvt. Ltd.VLSI Mentor
Captured output
11 21 31

The last fired on every outer pass, and the outer loop still completed all three of them. last leaves the loop it is written in, which here is the inner one.

That is correct and usually what you want. When it is not — when finding something in the inner loop should abandon the whole search — you need a label, and Chapter 9.6 is the chapter on it. The alternative people reach for first is a flag variable, which that chapter measures against the labelled version.

3. redo Does Not Advance

Azvya Education Pvt. Ltd.VLSI Mentor
redo-retry.pl
use strict;
use warnings;

my $tries = 0;

for my $item ("a", "b") {
    $tries++;
    if ($item eq "a" && $tries < 3) { redo }
    print "processed $item (tries so far $tries)\n";
}

print "total tries: $tries\n";
Azvya Education Pvt. Ltd.VLSI Mentor
Captured output
processed a (tries so far 3)
processed b (tries so far 4)
total tries: 4

A two-item list produced four passes. "a" was entered three times — twice redone, then processed on the third — and "b" once.

redo restarts the body with the same item. It does not move to the next element, and it does not re-test the loop condition. That is the whole of it, and it is also the hazard.

4. The continue Block, and the C Surprise

Perl loops can have a continue block, which runs after each pass. Almost nobody uses it, and the reason it exists is the measurement below.

Azvya Education Pvt. Ltd.VLSI Mentor
continue-block.pl
use strict;
use warnings;

my $c = 0;

for my $n (1 .. 3) {
    next if $n == 2;
}
continue {
    $c++;
}

printf "continue block ran %d time(s) for 3 items with one next\n", $c;
Azvya Education Pvt. Ltd.VLSI Mentor
Captured output
continue block ran 3 time(s) for 3 items with one next

Three times, not two. The next on item 2 skipped the rest of the body and the continue block still ran.

This is the opposite of what the name suggests to anyone coming from C, where continue is the keyword that does what Perl's next does. In Perl:

PerlC / SystemVerilog equivalent
nextcontinue
lastbreak
continue { }(no equivalent) — a block that always runs after each pass

So continue { } is the place for code that must run on every pass including the ones a next cut short — releasing something acquired at the top of the body, advancing a counter, logging the outcome.

In practice it is rarely needed, because a while loop can put the same code before the condition and a foreach usually has nothing to clean up. It is worth knowing for two reasons: you will eventually read one, and the word means the opposite of what your C instincts say.

5. Where These Keywords Earn Their Place

Azvya Education Pvt. Ltd.VLSI Mentor
guards.pl
use strict;
use warnings;

my @lines = (
    "# corner: ss",
    "",
    "alu   -0.120",
    "fifo   0.340",
    "BADROW",
    "regf  -0.050",
);

my $checked = 0;
my @failing;

for my $line (@lines) {
    next if $line =~ /^\s*$/;          # blank
    next if $line =~ /^\s*#/;          # comment

    my ($blk, $slack) = split ' ', $line;
    next unless defined $slack;        # malformed
    next unless $slack =~ /^[-+]?\d+(?:\.\d+)?$/;

    $checked++;
    push @failing, $blk if $slack < 0;

    last if @failing >= 2;             # stop at the second failure
}

printf "checked %d row(s), failing: %s\n", $checked, join(" ", @failing);
Azvya Education Pvt. Ltd.VLSI Mentor
Captured output
checked 3 row(s), failing: alu regf

Four next guards and one last, each on one line, with the real work at the left margin. The guards are in order of cheapness — two pattern tests, then a split, then a validity check — which is the conventional arrangement because the cheapest rejection should come first.

Note the validity guard: next unless $slack =~ /^[-+]?\d+/ rejects BADROW's missing field rather than comparing a non-number, which is Chapter 8.6's ordering rule applied inside a loop. A bare $slack < 0 on undef would have counted it as passing.

The last is the one to be careful with: it stops at the second failure, so checked is 3 rather than 4, and the loop did not examine the whole file. That is a deliberate early exit and the count reflects it — but if the summary were meant to describe the whole file, last would have made it a lie. An early last changes what your totals mean.

6. Why This Matters in Engineering Work

The guard stack is the shape of every parser. Skip blanks, skip comments, skip malformed rows, then work. Four next if lines read as a list of reasons to ignore a line, and the alternative is four levels of nesting.

last on a nested loop needs thought. A search that finds its answer in an inner loop and wants to stop everything needs a label, not a bare last — and a bare last there looks correct and keeps going.

redo is a hang risk, not just a rarity. It is the only loop-control keyword that can make a loop over a fixed list run forever, and it does so silently. If you meet one in inherited code, the first question is what the body changes to make its guard eventually false.

And an early last changes your denominators. "3 of 6 rows checked, 2 failing" is a different claim from "6 rows checked, 2 failing". A summary printed after a last has to say which it is.

7. Common Mistakes

Expecting last to exit all enclosing loops. It exits the innermost. Use a label.

redo with a guard the body never changes. The loop never ends, with no warning.

Forgetting to reset a retry counter between items. The second item inherits the first item's attempt count.

Reading Perl's continue as C's continue. Perl's next is C's continue; Perl's continue { } is a block that runs after every pass.

Expecting next to skip the continue block. It does not — measured 3 runs for 3 items with one next.

Using last or next in a do { } while. Fatal at run time.

Reporting totals after an early last without saying the loop stopped early.

Ordering guards from most to least expensive. Put the cheap rejections first.

8. Exercise

Exercise 1 — trace it. Run §1's loop over 1 .. 8. Then explain, in one sentence each, why 7 did not print and why 8 ended the loop. Swap the two guards and record what changes.

Exercise 2 — innermost only. Reproduce §2's nested loop. Confirm the output is 11 21 31 and state how many times the outer loop body ran.

Exercise 3 — redo counting. Run §3's two-item loop and record the total number of passes. Say how many times each item was entered.

Exercise 4 — the runaway. Write §3's callout loop with the die bound. Record the abort message and exit status. Then remove the redo and confirm the loop completes in three passes.

Exercise 5 — a bounded redo. Write a redo retry over three items where each item fails twice and succeeds on the third attempt, bounded by a counter. Confirm every item is processed and the counter resets between items. Then remove the reset and report what happens.

Exercise 6 — the nested-loop alternative. Rewrite Exercise 5 with an inner for my $attempt (1 .. 3) loop and last. Compare the two for length and for how obvious the retry limit is.

Exercise 7 — the continue block. Run §4's loop and confirm the count is 3. Then move the $c++ into the body after the next and record the new count.

Exercise 8 — the guard stack. Build §5's six-line input and the four guards plus the last. Record the checked count and the failing list. Then remove the last and record both again, and say which version you would print in a report and why.

9. Summary

  • next skips to the following item, last leaves the loop, redo re-runs the same item.
  • All three work in for, foreach, while, until and a bare block — and none works in do { } while, where they are fatal at run time.
  • Guard order is logic: measured, 7 was skipped by next and 8 stopped the loop, and swapping the guards changes which.
  • last exits only the innermost loop — measured, the outer loop completed all three passes. A label is needed to exit further out.
  • redo does not advance and does not re-test, so a two-item list produced four passes — and an unguarded redo never terminates.
  • redo is the only loop-control keyword that can hang a loop over a fixed list. Prefer a bounded inner retry loop.
  • Perl's next is C's continue. Perl's continue { } is something C has no equivalent for.
  • next does not skip the continue block — measured 3 runs for 3 items with one next.
  • Order guards cheapest-first, and validate a field before comparing it.
  • An early last changes what your totals describe. Say so in the summary.

Chapter 9.6 gives loops names, so last and next can act on an outer loop from inside an inner one — and removes the flag variable people otherwise write.

Where this fits

Part of the Perl curriculum.