The perldocs say the following about last
:
last
cannot be used to exit a block that returns a value such aseval {}
,sub {}
, ordo {}
, and should not be used to exit a grep() or map() operation.
Why should it be avoided in a grep() or map()? I'm especially curious about map since it is an alternative to the foreach construct. The docs seem to insist on not doing something without describing the consequences.
First, realise that grep
and map
are transparent to next
, last
and redo
, just like if
is.
$ perl -e'
print "A";
for (8,9) {
print "B";
print map { print "C"; next; print "D"; $_ } 1,2,3;
print "E";
}
print "F\n";
'
ABCBCF
But the docs doesn't say last
cannot be used to exit map
, it says it shouldn't used. It's not clear what that means.
map
and grep
?map
and grep
?I don't know.
I don't think it's #3 because I don't know of any bad side-effects of using next
, last
and redo
to leave a map
or grep
callback.
The funny thing, leaving map
and grep
using a loop construct doesn't even warn even though leaving a sub in the same fashion does.
$ perl -wE'while (1) { map { last; } 1; }'
$ perl -wE'while (1) { sub { last; }->(); }'
Exiting subroutine via last at -e line 1.
map
is meant for mapping one list to another. It certainly isn't an alternative to foreach
. I have seen too often things like
map { print "$_\n" } @data;
which commits the sin of using map
for its side-effects and throwing away the resulting list. You wouldn't consider using
my $x = 99;
sqrt(my $y = $x * $x);
print $y;
and you would get a warning. For the same reason you shoudn't use map
when you mean for
.
For a practical reason, consider
print "A";
print map { print "B"; last; print "C";} 1,2,3;
print "Z";
OUTPUT
AB
so in this case the last
exits the entire program. In general, using last
or next
inside a map
or grep
block exits the containing block, if there is one, otherwise the entire program. This is something to be avoided, hence "last
... should not be used to exit a grep() or map() operation".
In Perl, there is a decent amount of functionality overlap between for/foreach
, grep
, and map
. However, just because you can potentially use them all to solve the same problem, doesn't mean that they're all the best tool for that particular job (see: using a screwdriver to pound a nail).
grep
: Its purpose is to filter a list and return the resulting subset.map
: Its purpose is to modify a list and return the resulting modified list.for/foreach
: Its purpose is to iterate through a list and do something.Now, you can accomplish every use of grep
and map
with for/foreach
. grep
and map
are basically syntactic sugar for specific uses of list processing (for/foreach
) that are particularly common and useful. By design, by convention, and by best practices, they trade certain things for increased convenience and clarity.
One of those things, is that grep
and map
are intended to return a value. Using them in void context is discouraged, and considered to violate idiomatic Perl. If you aren't returning a value, use for/foreach
. If you are returning a value, then last
interrupts that process.
If you are following best practices for Perl, your use of grep
and map
will always be returning a value, which means that using last
should be avoided.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With