Spot the error
Spent 10 minutes the other day scratching my head after my Perl code stopped working following a single added line (can you guess which one?):
LABEL1:
my @var;
for (...) {
next LABEL1;
}
The error message is "Label not found for 'next LABEL1'. I think Perl could be better at handling this kind of mistake.
I think this is not a mistake.
next, last should not jump to out of the block.
Never ever ever ever ever use labels.
Labels are awesome.
@Mike: why not? Here's some code from my Class::Sniff module:
CLASS:
for my $class (@$classes) {
my $method_found = 0;
for my $path (@paths) {
# method was found in a *previous* path.
if ($method_found) {
push @unreachable => "$class\::$method";
next CLASS;
}
for my $curr_class (@$path) {
next CLASS if $curr_class eq $class;
if ( not $method_found && $curr_class->can($method) ) {
$method_found = 1;
}
}
}
}
The label makes that code much easier to read and work with. How would you rewrite it?
For breaking out of inner loops I prefer to set a flag and use
last
. Or separate the inner loop into a subroutine andreturn
something useful.I know some people consider that more obfuscated, but in my opinion the use of labels on loops is identical to a
goto
; it makes a program unstructured. Sometimes a little more code can be clearer than a concise solution.That said, I'm not one to stick to dogma at all costs. All tools are useful, and I'm sure there are uses of labels out there that I could stomach.
@Mike -- Labels are an awesome, underappreciated Perl feature. From "perldoc -f goto":
Labels provide a form of non-local control transfer that can be much more clear and concise than eval/die. For example, given a function like this: your callback, or a function it calls, can easily break out of search_big_thing with "last SEARCH_BIG_THING".@educated, that strikes me as a really bad idea. A callback should never be responsible for altering the flow of the caller. What's wrong with
sub search_big_thing(&) {
while( $_ = next_big_thing ) {
my $found_it = $_[0]->();
last if $found_it;
}
}
Bonus: now the callback sub is not bound to an arbitrary label name, and is thus reusable.
Mike, AFAICT you missed my point. Let's try another example:
Also, "A callback should never be responsible for altering the flow of the caller" imples that a callback should never throw exceptions. Really?
That's a pretty contrived example, I think. You'd have to be batty to design a search algorithm with five nested loops.
But in the miniscule chance that you actually have something like that, I suppose using a label is fine.
We'll just have to agree to disagree, then... But let's say you have a map, nicely stored as a quad tree, and you want to find something on that map. How do you do it? More generally, let's say you have a hierarchical data structure, and you want to search it. Or is that too contrived?