redo#
Restart the current iteration of a loop without re-testing the
condition and without running the continue block.
redo jumps back to the top of the loop body and re-runs it on the
same input — the conditional that guards the loop is not
re-evaluated, $_ is not advanced by while (<FH>), the iterator of
a foreach is not advanced, and any continue { } block attached to
the loop is skipped. The current pass happens again from the
beginning.
Synopsis#
redo
redo LABEL
redo EXPR
What you get back#
redo does not return a value. It is a flow-control operator: it
transfers control and never falls through to the next statement. Do
not try to use it as the value of an expression — in particular, it
cannot be used to return a value from eval { }, sub { }, or
do { }.
Which loop it targets#
With no argument, redo refers to the innermost enclosing loop.
With a LABEL, it restarts the loop tagged with that label, allowing
you to reach out of nested loops:
OUTER: while (...) {
while (...) {
redo OUTER; # restart the while (...) above
}
}
redo EXPR (added in Perl 5.18) computes the label at runtime. The
expression must evaluate to a string naming a label currently in
scope:
my $target = "OUTER";
redo $target;
A bare block counts as a loop that runs once, so redo inside a
block turns it into a looping construct:
{
my $line = <STDIN>;
redo if $line =~ /^\s*$/; # skip blank lines, re-read
print $line;
}
redo vs next vs last#
All three take an optional LABEL and all three affect loop control,
but they differ in what they skip:
next— go to the next iteration.continueblock is run, then the loop condition is re-tested.redo— re-run the same iteration.continueblock is not run, and the loop condition is not re-tested.
The continue-block difference is the one that catches people out.
If a loop uses continue { } to increment a counter or advance a
cursor, redo will not advance it — that’s the whole point, but it
is also the whole foot-gun.
Examples#
Re-prompt until the user gives valid input. The continue block is
skipped, so $attempts only counts completed iterations, which is
usually what you want:
my $attempts = 0;
while (1) {
print "Enter a positive integer: ";
my $n = <STDIN>;
chomp $n;
redo unless $n =~ /^[0-9]+$/ && $n > 0;
print "Got $n after $attempts rejected tries.\n";
last;
} continue {
$attempts++;
}
Restart processing of the current line after patching it — the classic “lie to yourself about what was just read” pattern, here stripping Pascal-style block comments that may span multiple input lines:
LINE: while (<STDIN>) {
while (s|({.*}.*){.*}|$1 |) {}
s|{.*}| |;
if (s|{.*| |) {
my $front = $_;
while (<STDIN>) {
if (/}/) { # end of comment?
s|^|$front\{|;
redo LINE; # re-process the patched line
}
}
}
print;
}
Target an outer loop by label. redo INNER would restart the inner
loop on the current $x; redo OUTER restarts the outer loop on the
current $x without advancing the foreach iterator:
OUTER: foreach my $x (@xs) {
INNER: foreach my $y (@ys) {
redo OUTER if should_restart($x, $y);
}
}
Turn a bare block into a retry loop. Without redo this block runs
exactly once; with redo it runs until the fetch succeeds:
my $tries = 0;
{
my $ok = try_fetch();
if (!$ok && ++$tries < 3) {
sleep 1;
redo;
}
}
Edge cases#
continueis not run. This is the defining difference fromnext. If your loop relies oncontinue { }for counters, cursors, or cleanup,redowill bypass all of it. Either move the work into the body or usenextinstead.Loop condition is not re-tested.
while (cond) { ... redo; }will keep looping even ifcondwould now be false. You are responsible for ensuring theredopath eventually exits vialast,return, or a conditional fall-through.Easy infinite loop.
redowith no state change is a tight infinite loop — typically not what you want. Always pairredowith a condition that eventually becomes false, or with a retry counter that triggerslast.foreachdoes not advance.foreach my $x (@xs) { redo }keeps$xpinned at the current element and loops on it forever. The iterator only advances on fall-through ornext.while (<FH>)does not read the next line.$_retains the current line across theredo, which is precisely why the Pascal comment stripper above works.redoout ofgrep/mapis not supported. Upstream documents this as undefined; do not useredoto exit or restart agrep BLOCK LISTormap BLOCK LIST.redoout ofeval,sub, ordois not a return. It performs flow control; there is no value to return. Aredothat would have to cross such a boundary to reach a loop is a runtime error (“Can’tredooutside a loop block”).Precedence quirk. Unlike most named operators,
redohas the precedence of assignment and is exempt from the looks-like-a-function rule.redo ("foo")."bar"passes the whole concatenation as the argument toredo— the parentheses do not isolate"foo".
Differences from upstream#
Fully compatible with upstream Perl 5.42.
See also#
last— exit the loop entirely;continueblock is not run, same asredonext— advance to the next iteration;continueblock is run and the loop condition is re-testedreturn— return from the enclosing subroutine, not just the loop; unlikeredo, it yields a valuecontinue— the block thatredoskips butnextruns; the core of the three-way distinction