Michael Limberger
Need me? Email mike@limberger.ca
Perl
Self-modifying loops
A countdown with no for, no while
This note continues the self-modifying loop thread. Same territory as the earlier talk notes: useful when you want to see the machinery, not just the tidy answer.
You are welcome if you can read a few lines of Perl, or if you are willing to pause on a glyph and ask what it does. This is not a pattern for work code. It is the language handing you a chainsaw.
#!/usr/bin/env perl
use feature qw|say|;
$_ = <<'EOF';
10;
s~(\d+)(?{ say qq($1) })~$1-1~e;
sleep 1;
$1 ? eval : say q(Countdown complete!);
EOF
eval;
Run it. It counts from 10 to 1. No for. No
while. A heredoc that eats itself.
Stuffing code into a string
A variable is a named box. $_ is Perl's
default box. The $ on the front is the
sigil: it says this box holds one value.
A heredoc is a quoted block that runs until a marker,
here EOF. Single quotes around the marker mean
no interpolation yet. The text is just text. It happens to
be valid Perl. Then we run it.
A number sitting there
10;
In Perl a bare number is a valid statement. It evaluates to itself and does nothing. It is sitting in the string so a regex can find it.
The substitution that eats itself
s~(\d+)(?{ say qq($1) })~$1-1~e;
s~~~ is substitution. The ~ is just
the delimiter, the same job / usually has.
(\d+) | Capture digits into $1. |
|---|---|
(?{ ... }) | Embedded code. Runs during the match. |
say qq($1) | Print the captured number. |
$1-1 | Replacement: the number minus one. |
e | Evaluate that replacement as Perl. |
After one pass, the string "10;..." becomes
"9;...". The program is rewriting itself.
When to stop
$1 ? eval : say q(Countdown complete!);
A ternary is a one-line if. If $1 is
truthy, eval runs the string again. When the
number hits zero, Perl treats it as false, and the goodbye
prints.