in reply to Perl Best Practices - Loop Labels

I am surprised at your use of loop labels. In my experience this is a very rare thing. I have used a Perl loop label maybe once in the past few years. Unfortunately, I haven't found that example yet in my code base - perhaps my grep kung fu is failing?

The normal way (in my opinion) to exit completely from an inner and outer loop in C or Perl is to use a return statement. You put the loops in a subroutine and use an embedded return statement. Yes, there are some folks who advocate for adding a conditional flag like: while(...and !$end_flag){}, where inside the loop the code sets $end_flag=1 to end the loop. The theory behind that is that the code should only one way in and only one way out. However, I believe that if the code is short (<1/3-1/2 page), having an intermediate "return" is no big deal. This is often an ERROR return and will have some sort of #ERROR comment.

sub XXX { #sub setup params... for (...) { next if $cond1; for (...) { ... last if $cond2; # next OUTER if $cond2 ... last if $cond3; # next OUTER if $cond3; # WHAT? # INNER vars do not remain the same ... return() if $cond4; # same as last OUTER ... next if $cond5; # redundant all cndx are next ... } return if $condx6; #early return } return }
In your pseudo code, there appears to be some assumption that going back to the outer loop somehow maintains the inner loop vars. I said "WHAT?". Perhaps you have a relatively short example that you could post and the Monks could have a go at it? I didn't understand completely the intent of your pseudo code.

In general, the loop conditional should express the conditions upon which the loop normally terminates.

Replies are listed 'Best First'.
Re^2: Perl Best Practices - Loop Labels
by kcott (Archbishop) on Apr 16, 2020 at 08:47 UTC

    G'day Marshall,

    "The normal way (in my opinion) to exit completely from an inner and outer loop in C or Perl is to use a return statement."

    Sorry, but that's completely wrong. The return function is for exiting a subroutine, not a loop. The first sentence of the last documentation starts (my emphasis):

    "The last command is like the break statement in C ..."

    Consider this code which uses last:

    $ perl -E 'X(); sub X { for (0..2) { last if $_ > 1; say; } say 42; }' 0 1 42

    Now this code, which is identical in all respects, except last has been replaced by return:

    $ perl -E 'X(); sub X { for (0..2) { return if $_ > 1; say; } say 42; +}' 0 1

    Note how the say 42; is not executed in that second example.

    "Yes, there are some folks who advocate for adding a conditional flag like: while(...and !$end_flag){}, where inside the loop the code sets $end_flag=1 to end the loop. The theory behind that is that the code should only one way in and only one way out."

    I addressed "structured programming techniques" in my OP.

    "In your pseudo code, there appears to be some assumption that going back to the outer loop somehow maintains the inner loop vars."

    No, I have made no such assumption.

    Although I do have some other issues with what you've written, I'll leave it there for now.

    — Ken

      Your wrote: "Sorry, but that's completely wrong. The return function is for exiting a subroutine, not a loop. The first sentence of the last documentation starts (my emphasis):

      If you look at my code, I put both loops within a subroutine, XXX. If the inner loop needs to abort the outer loop, a return statement is appropriate. Of course you have to refactor the code into a subroutine so that return from the inner loop aborts the outer loop.

      If you don't do that then, you get to this stuff where inner loop has to set a flag that causes the outer loop to finish. Put both loops in a sub and just return from the inner loop when no more processing is necessary.

      As far as return() goes, this would be more like I describe based upon your code:

      use strict; use warnings; x($_)for (0..5); #sub x won't print any num >1 print "42\n";; sub x { my $num = shift; return if $num >1; print "$num\n"; } __END__ Prints: 0 1 42
      This can be expanded to deal with 2 or more dimensions.