Alternative to "last" in do loops - perl

According to the perl manual for for last (http://perldoc.perl.org/functions/last.html), last can't be used to break out of do {} loops, but it doesn't mention an alternative. The script I'm maintaining has this structure:
do {
...
if (...)
{
...
last;
}
} while (...);
and I'm pretty sure he wants to go to the end of the loop, but its actually exiting the current subroutine, so I need to either change the last or refactor the whole loop if there is a better way that someone can recommend.

Wrap the do "loop" in a bare block (which is a loop):
{
do {
...
if (...)
{
...
last;
}
} while (...);
}
This works for last and redo, but not next; for that place the bare block inside the do block:
do {{
...
if (...)
{
...
next;
}
...
}} while (...);

do BLOCK while (EXPR) is funny in that do is not really a loop structure. So, last, next, and redo are not supposed to be used there. Get rid of the last and adjust the EXPR to evaluate false when that situation is found.
Also, turn on strict, which should give you at least a warning here.

Never a fan of do/while loops in Perl. the do isn't really a loop which is why last won't break out of it. In our old Pascal daze you couldn't exit a loop in the middle because that would be wrong according to the sage Niklaus "One entrance/one exit" Wirth. Therefore, we had to create an exit flag. In Perl it'd look something like this:
my $endFlag = 0;
do {
...
if (...)
{
...
$endFlag = 1;
}
} while ((...) and (not $endFlag));
Now, you can see while Pascal never caught on.

Why not just use a while loop?
while (...) {
...
if (...) {
last;
}
}
You might have to change your logic slightly to accommodate the fact that your test is at the beginning instead of end of your loop, but that should be trivial.
By the way, you actually CAN break out of a Pascal loop if you're using Delphi, and Delphi DID catch on for a little while until Microsoft wised up and came out with the .net languages.

# "http://perldoc.perl.org/functions/last.html":
last cannot be used to exit a block that returns a value such as eval {} , sub {} or do {} , and should not be used to exit a grep() or map() operation.
So, use a boolean in the 'while()' and set it where you have 'last'...

Late to the party - I've been messing with for(;;) recently. In my rudimentary testing, for conditional expressions A and B, what you want to do with:
do {
last if A;
} while(B);
can be accomplished as:
for(;; B || last) {
last if A;
}
A bit ugly, but perhaps not more so than the other workarounds :) . An example:
my $i=1;
for(;; $i<=3 || last) {
print "$i ";
++$i;
}
Outputs 1 2 3. And you can combine the increment if you want:
my $i=1;
for(;; ++$i, $i<=3 || last) {
print "$i ";
}
(using || because it has higher precedence than ,)

Related

Odd use of False constant in if-then statement

Python is my main language, but have to maintain a rather large legacy Perl codebase.
I have an odd logic statement that I can't make heads or tails over.
At top, a constant is defined as:
use constant FALSE => 0;
sub thisFunc {
FALSE if ($self->{_thisVar} ne "tif");
...
...
return statement,etc..
}
So I'm reading that as a kinda' fancy, non-standard if-then statement,
that if $thisVar string is not equal to "tif", then FALSE. Huh?
Not something like $that = FALSE, just FALSE.
The form of this statement appears in the file several times.
This codebase is in use, and vetted over the years by very good team,
so I think it is valid and has meaning. "use strict;" is set at top.
Could someone be so kind as to explain what is meant by logic.
I've Google'd it but no joy.
Thanks in advance,
"if" logic in Perl can be constructed in couple of ways:
the obvious one:
if ($flag) { do_something() }
less obvious one:
do_something() if ($flag);
This example shows how exactly behaves that odd "FALSE if" statement - which only meaning is found when it is LAST statement in subroutine:
use strict;
use constant FALSE => 0;
sub thisFunc {
my $arg = shift;
FALSE if ($arg ne "tif");
}
print "return val: ".thisFunc("ble")."\n";
print "return val: ".thisFunc("tif")."\n";
output from running above is:
return val: 0
return val:
It is pointless. I suspect it's suppose to be
return FALSE if $self->{_thisVar} ne "tif";
There is a similar construct that isn't pointless. If the loop condition has side-effects, the following isn't pointless:
1 while some_sub();
aka
while (some_sub()) { }
aka
while (1) {
some_sub()
or last;
}
Practical example:
$ perl -E'$_ = "xaabbx"; 1 while s/ab//; say'
xx

Perl function/sub best practice

I have a really quick question. I have a program with a lot of functions that are run from main. Is it best practice to have the functions first and then the call from main, or the other way around?
For example:
sub myFunction {
#Do something
}
my $stuff = myFunction();
Or:
my $stuff = myFunction();
sub myFunction {
#Do something
}
Sorry for any ignorance, I do not have any formal training and I have seen it done both ways online. Thanks
I recommend placing your code at the bottom.
Issue 1
The latter snippet poor because myFunction is in scope of $stuff, but it shouldn't be. That's easy to fix though.
{
my $stuff = myFunction();
}
sub myFunction {
#Do something
}
Ok, so that's not a big issue since I place all top-level code in a block, even if it comes at the end. It looks cleaner to me that way, and it makes it easier to transform into a sub from which I can return.
sub myFunction {
#Do something
}
sub main {
return 0 if is_nothing_to_do();
my $stuff = myFunction();
...
return 0;
}
exit(main(parse_args));
Issue 2
Many languages require that you declare your subs before you call them. That's rarely needed in Perl, though there are a couple of scenarios where it is required. Subs with prototypes is one of those. If you wanted to place your code at the top, you would need to add declarations even before that.
sub myFunction(&#);
{
my $stuff = myFunction { ... } ...;
}
sub myFunction(&#) {
#Do something
}
You probably never have to do that since all but some rare uses of prototypes is discouraged, and the other scenarios are even rarer.
Issue 3
You might accidentally skip initialization code by placing your top-level code before your subroutines.
Compare:
print my_counter(), "\n"; # Warns, then prints a blank line
...
{
my $counter = 1;
sub my_counter {
return $counter++;
}
}
...
and
...
{
my $counter = 1;
sub my_counter {
return $counter++;
}
}
...
print my_counter(), "\n"; # Prints 1
Issue 4
Many languages require that you declare your subs before you call them, so more people will be more familiar with having the top-level code at the bottom.
It doesn't matter, so long as you're able to find the code that you need to find. I typically like to set up my code like this:
use strict;
use warnings;
exit main();
sub main {
do_this();
dont_do_that();
cant_you_read_the_signs();
return 0;
}
sub do_this {
....
}
...
Putting your main code in an actual function or block called "main" helps keep you from polluting the program with globals.

Perl do...while and last command

I've just encountered some very weird behavior that I really can't explain:
do {
my $qry = $self->getHTMLQuery(undef, $mech->content());
next if (!defined($qry));
push(
#prods,
map { 'http://www.XXXXYYYX.com'.$_->attr('href') }
$qry->query('div.prodInfo div.prodInfoBox a.prodLink.GridItemLink')
);
$qry->delete();
$TEST++;
last if ($TEST >= 10);
} while(eval { $mech->follow_link(class => 'jump next') });
print "WHILE ENDED\n";
The code above never prints "WHILE ENDED" even though it does seem to go out of the while loop when $TEST >= 10.
But the following code does print "WHILE ENDED":
do {
my $qry = $self->getHTMLQuery(undef, $mech->content());
next if (!defined($qry));
push(
#prods,
map { 'http://www.XXXXYYYX.com'.$_->attr('href') }
$qry->query('div.prodInfo div.prodInfoBox a.prodLink.GridItemLink')
);
$qry->delete();
$TEST++;
} while(eval { $mech->follow_link(class => 'jump next') } && $TEST <= 10);
print "WHILE ENDED\n";
In both tests, the initial value of $TEST is 0.
Is the behavior of last in do...while different than in for and while {...}?
A do block with a looping modifier doesn't count as a real loop as far as next, last, and redo are concerned. This is mentioned in perlsyn, where you'll find the tip Schwern mentioned about surrounding it with a bare block to make last work. But that won't work with next, because a bare block is only executed once, so next acts like last. To make next work, you can put the bare block inside the do, but then last will act like next.
If you need both next and last to work with a do ... while, the easiest way is to use an infinite loop with the real condition in a continue block. These 2 loops are equivalent, except that the second is a real loop, so it works with next & last:
do { ... } while condition;
while (1) { ... } continue { last unless condition };
From perldoc -f last:
"last" cannot be used to exit a block that returns a value such as
"eval {}", "sub {}" or "do {}"
TLP is right. The standard work around for this (I just hit it myself) is to wrap the do/while in a bare block which, counter-intuitively, does respect loop controls.
{ do {
last;
} while 1; }
The block outside will catch last. If you want to handle next you have to put the bloc inside.
do {{
next;
}} while 1;
The block inside will catch next.
Unfortunately you can't do both.

What does for (;;) mean in Perl?

I was looking though a fellow developers code when I saw this ..
for (;;){
....
....
....
}
I have never seen ";;" used in a loop. What does this do exactly?
It loops forever. ';;' equates to no start value, no stop condition and no increment condition.
It is equivalent to
while (true)
{
...
}
There would usually be a conditional break; statement somewhere in the body of the loop unless it is something like a system idle loop or message pump.
All 3 parts are optional. An empty loop initialization and update is a noop. An empty terminating condition is an implicit true. It's essentially the same as
while (true) {
//...
}
Note that you it doesn't have to be all-or-nothing; you can have some part and not others.
for (init; cond; ) {
//...
}
for (; cond; update) {
//...
}
for (init; ; update) {
//...
}
Just like in C, the for loop has three sections:
a pre-loop section, which executes before the loop starts.
a continuing condition section which, while true, will keep the loop going.
a post-iteration section which is executed after each iteration of the loop body.
For example:
for (i = 1, acc = 0; i <= 10; i++)
acc += i;
will add up the numbers from 1 to 10 inclusive (in C and, assuming you use Perl syntax like $i and braces, in Perl as well).
However, nothing requires that the sections actually contain anything and, if the condition is missing, it's assumed to be true.
So the for(;;) loop basically just means: don't do any loop setup, loop forever (breaks notwithstanding) and don't do any iteration-specific processing. In other words, it's an infinite loop.
Infinite loop. A lot of the time it will be used in a thread to do some work.
boolean exit = false;
for(;;) {
if(exit) {
break;
}
// do some work
}
Infinite Loop (until you break out of it).
It's often used in place of:
while(true) { // Do something }
It's the same as
while(true) {
...
}
It loops forever.
You don't need to specify all of the parts of a for loop. For example the following loop (which contains no body, or update token) will perform a linear search of myArray
for($index = -1; $myArray[++$index] != $target;);

How can I cleanly handle error checking in Perl?

I have a Perl routine that manages error checking. There are about 10 different checks and some are nested, based on prior success. These are typically not exceptional cases where I would need to croak/die. Also, once an error occurs, there's no point in running through the rest of the checks.
However, I can't seem to think of a neat way to solve this issue except by using something analogous to the following horrid hack:
sub lots_of_checks
{
if(failcond)
{
goto failstate:
}
elsif(failcond2)
{
goto failstate;
}
#This continues on and on until...
return 1; #O happy day!
failstate:
return 0; #Dead...
}
What I would prefer to be able to do would be something like so:
do
{
if(failcond)
{
last;
}
#...
};
An empty return statement is a better way of returning false from a Perl sub than returning 0. The latter value will actually be true in list context:
sub lots_of_checks {
return if fail_condition_1;
return if fail_condition_2;
# ...
return 1;
}
Perhaps you want to have a look at the following articles about exception handling in perl5:
perl.com: Object Oriented Exception Handling in Perl
perlfoundation.com: Exception Handling in Perl
You absolutely can do what you prefer.
Check: {
last Check
if failcond1;
last Check
if failcond2;
success();
}
Why would you not use exceptions? Any case where the normal flow of the code should not be followed is an exception. Using "return" or "goto" is really the same thing, just more "not what you want".
(What you really want are continuations, which "return", "goto", "last", and "throw" are all special cases of. While Perl does not have full continuations, we do have escape continuations; see http://metacpan.org/pod/Continuation::Escape)
In your code example, you write:
do
{
if(failcond)
{
last;
}
#...
};
This is probably the same as:
eval {
if(failcond){
die 'failcond';
}
}
If you want to be tricky and ignore other exceptions:
my $magic = [];
eval {
if(failcond){
die $magic;
}
}
if ($# != $magic) {
die; # rethrow
}
Or, you can use the Continuation::Escape module mentioned above. But
there is no reason to ignore exceptions; it is perfectly acceptable
to use them this way.
Given your example, I'd write it this way:
sub lots_of_checks {
local $_ = shift; # You can use 'my' here in 5.10+
return if /condition1/;
return if /condition2/;
# etc.
return 1;
}
Note the bare return instead of return 0. This is usually better because it respects context; the value will be undef in scalar context and () (the empty list) in list context.
If you want to hold to a single-exit point (which is slightly un-Perlish), you can do it without resorting to goto. As the documentation for last states:
... 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.
sub lots_of_checks {
local $_ = shift;
my $all_clear;
{
last if /condition1/;
last if /condition2/;
# ...
$all_clear = 1; # only set if all checks pass
}
return unless $all_clear;
return 1;
}
If you want to keep your single in/single out structure, you can modify the other suggestions slightly to get:
sub lots_of_checks
{
goto failstate if failcond1;
goto failstate if failcond2;
# This continues on and on until...
return 1; # O happy day!
failstate:
# Any clean up code here.
return; # Dead...
}
IMO, Perl's use of the statement modifier form "return if EXPR" makes guard clauses more readable than they are in C. When you first see the line, you know that you have a guard clause. This feature is often denigrated, but in this case I am quite fond of it.
Using the goto with the statement modifier retains the clarity, and reduces clutter, while it preserves your single exit code style. I've used this form when I had complex clean up to do after failing validation for a routine.