Else Clauses on Loops

I am curious whether anyone else would like to see else clauses applied to for/foreach and while loops,  where the code in the else clause would be executed if the loop body was completely skipped due to the conditions/boundaries. So for example:

…with a for/foreach loop:

for my $temperature ($temp_lower_bound .. $temp_upper_bound) {
  set_temperature($temperature, $soak_time);
  push @data, get_sensor_reading();
}
else {
  die "Temperature upper bound must be greater than lower bound!\n";
}

foreach my $datum (@data) {
  print "processing $datum...\n";
  process($datum);
}
else {
  warn "No data!\n";
}

…with a while loop:

open LOG_FILE, "<", $log_file
  or die "Could not open log file: $!\n";
while (<LOG_FILE>) {
  process_log_entry($_);
}
else {
  print "The log file was empty!\n";
}
close LOG_FILE;

Obviously all of these examples could be implemented by wrapping the loop in an ifthenelse that checks the condition or boundaries, or by setting a “ran once” flag in the body and checking it after, but those solutions—that I use all the time—seem unwieldy and inelegant to me.

Note this isn’t a Perl-specific concept; it could apply to almost any procedural programming language. (Does it already exist anywhere else?)

11 Comments

Fwiw, there is no need to ever use foreach other than to give newbies very wrong impressions about it doing anything different. It is exactly as useless as the human appendix, because it does nothing that for doesn't already do, in fact if you look at toke.c you'll find it is literally the same code path:

case KEY_for:
case KEY_foreach:

As for the else proposal, i can see it being useful. However to get more useful input you'd be better off mailing this to p5p. :)

I like to use "foreach" specifically because that reflects that I am using the form that is different from the usual (as perpetrated by C) "for". But I'll still use "for" for terseness in postfix syntax.

for (@x) {
    last
}
else {
    ...
}
say 123;

It has too much "goto" smell for my taste, where inner block flow control can jump over outer scope block.

Also "else" is a boolean word. And this may lead to confusion in situations like this.

my @x =(0):
while (shift @x) {
    ...
}
else {
    ...
}
say 123;

Does it count as iteration if array was not empty, array item was checked but first block was never entered?

As far as I know, only Python currently has an explicit for...else syntax. But it doesn't exactly do what you're proposing. Indeed, the else clause runs if the loop completes successfully. So, you skip it by doing break (last to us Perlers). Python 2: https://docs.python.org/2/tutorial/controlflow.html#break-and-continue-statements-and-else-clauses-on-loops and no change in Python 3: https://docs.python.org/3/tutorial/controlflow.html#break-and-continue-statements-and-else-clauses-on-loops

Nonetheless I'd find the proposed syntax useful especially in a grep context:

for my $i ( grep defined, @stuff ) {
    say $i;
}
else {
    say "Nothing was defined";
}

Which is shorter and easier to read than:

my @defined_stuff = grep defined, @stuff;
if ( !@defined_stuff ) {
    say "Nothing was defined";
}
for my $i ( @defined_stuff ) {
    say $i;
}

But, here's a thread about Perl 6 adopting a similar feature, which ended up in the negative: https://groups.google.com/forum/#!topic/perl.perl6.language/6PbCdjvhi14 But their for loop is an expression, not a statement, and returns a value.

And if you want this now, here's the Perl 5 For::Else module: https://metacpan.org/pod/For::Else But it's a source filter. Someone could update it to Perl 5.14's syntax plugins though, to test out the feature.

Regarding the syntax, it could definitely be a useful feature. My concern would be that its meaning is somewhat vague at first glance, especially since (as others mentioned) python has a similar syntax which works very strangely. Also consider things like: would it fire the 'continue' block (as this can be attached to either 'while' or 'foreach' loops)?

Hi Mithaldu

JFTR The appendix is not useless. When recovering from illness your body can preferentially pump 'good' bacteria (i.e. part of the microbiome - Wikipedia) out of the appendix to re-populate the rest of the intestine. Fact of the Week!

Cheers

Haha, alright Ron, thanks for the information, neat to know. Really breaks my comparison. :)

Grinnz: Could you maybe post a direct link to a guide on how to write something with the syntax plugins?

Leave a comment

About morandimus

user-pic My real name is Jeremy Holland. I've been a programmer for 25 years, using primarily Perl since 2000.