while (1) {
do_stuff;
do_some_checks;
do { warn error 1; last } if not OK;
do_more_stuff;
do_some_checks;
do { warn error 2; last } if not OK;
do_even_more_stuff;
do_some_checks;
do { warn error 3; last } if not OK;
...
#finally
last;
}
I prefer it over the one below:
do_stuff;
do_some_checks;
if (!OK) {
warn error 1;
} else {
do_more_stuff;
do_some_checks;
if (!OK) {
warn error 2;
} else {
do_even_more_stuff;
do_some_checks;
if (!OK) {
...
}
# finally
success!
}
}
The
while (1) { ... last ... }
style is clearer and avoids extraneous indentation. The only thing biting me in the past when using this construct is that sometimes I forgot to add the final last
, resulting in an infinite loop. But this series-of-checks-and-early-bail pattern happens so often in my code that the construct quickly became second nature.Anyone got the same habit, or perhaps using some alternative (like the new
given-when
)?
Just leave out the 'while (1)' part. If you read the documentation for last it says: "Note that a block by itself is semantically identical to a loop that executes once. Thus "last" can be used to effect an early exit out of such a block."
BalasHapusTry it with: perl -lE '{ say "Hello"; last; say "Bye"}'
Only the 'Hello' gets printed.
There's a much nicer way to do this, I like to call it the "make subroutines" pattern ;)
BalasHapusPut the series of checks into a subroutine, then simply call "return" whenever a check fails.
This is much clearer than either of your two options up there, and has the bonus of giving you a chance to introduce a useful name for a block of code.
Whenever you find yourself going into contortions to avoid lots of nested ifs, consider making a new subroutine.
@pmakholm: Thanks for pointing that out! Perl never ceases to give nice surprises (as well as not so nice ones but those are rarer).
BalasHapus@Dave: Usually the construct already forms the outermost layer of a sub. I just need to do some stuffs before returning. E.g.:
# returns [HTTP status code, error msg, result]
sub foo {
my @resp = (500, "Error");
{
stuff...
{ @resp = (404, "Not found"); last } if not OK;
stuff..
last if not OK;
...
@resp = (200, "OK", $res);
}
wantarray ? @resp : $resp[2];
}
Unfortunately there is no equivalent for the short '{...last...}' Perl idiom in PHP.
BalasHapusI also realized that you can do this instead to avoid writing the final 'last':
# Perl
for(1) { # do only once
...
}
# PHP
do { # do only once
...
} while (0);
Feel kind of silly for having written hundreds of avoidable 'last' statements now. :-)
Thanks everybody.