develooper Front page | perl.perl6.language | Postings from April 2002

Loop controls

From:
Miko O'Sullivan
Date:
April 25, 2002 09:38
Subject:
Loop controls
Message ID:
001101c1ec77$28581890$040a0a0a@mosullivan
SUMMARY

A proposal for a set of loop structures that simplify code that is based on
loop iterations.

 foreach my $var (@arr) { ... }
 before  { ... }     # run before first iteration, only if there is at least
one iteration
 between { ... }   # run between iterations, not before first or after last
 after   { ... }       # run after last iteration, only if there is at least
one iteration
 noloop  { ... }    # run if there are no iterations


DETAILS

Virtually every time I write code for a loop I need to do some set of stuff
before the loop (if there were actually any loops), some more stuff after
the loop (again, only if there were actually any loops), and yet another
bunch of stuff if there were no loops at all.  I also frequently need to do
something only between loops, but not before or after.  For example, suppose
the code loops though the results of a search.  The code should output a
header at the top, a footer at the bottom, an <HR> between each loop, and
should do none of that if nothing was found.  (This example is only slightly
exagarated: except for the <HR> in between, all my searches do all of that.)
Currently we would implement these requirements using an iteration counter:

  my $counter = 0;

  foreach my $res ($myob->getresults) {
     if ($counter) {
     # output divider
  }

  else {
     # output header
  }

  # do stuff to display the result

  $counter++;
  }


  # close if there were any loops
  if ($counter) {
     # output footer
  }

  # lack of results message if no loops
  else {
     # print "no results" message
  }

Now, I'll be the first to admit that that isn't a terribly complicated
algorithm, but it took me while to come up with that algorithm and it always
feels like I have to contort my code to make it work... the header goes
inside the loop when I feel like it should go before the loop, the divider
comes before the header (or I have to use "if not", which means doing a
confusing test for a negative).  The proposed solution is similar to the
benefit foreach gave us: it just makes things easier.  It organizes the code
into logical blocks based on the process of looping through the elements:

  before {
    # output header
  }

  foreach my $res ($myob->getresults) {
  # do stuff to display the result
  }

  between {
     # output divider
  }

  # footer if there were any loops
  after {
     # output footer
  }

  # lack of results message if no loops
  noloop {
     # print "no results" message
  }


The blocks should go outside the loop, not inside like has been discussed
for other loop controls.  None of these structures are about the process
inside any particular iteration... they are always outside of any specific
iteration.  Also, it would make sense to allow "before" to go before the
loop... after all, it's stuff that happens before the loop.

-Miko




nntp.perl.org: Perl Programming lists via nntp and http.
Comments to Ask Bjørn Hansen at ask@perl.org | Group listing | About