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 if…then…else 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?)
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.
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.
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, theelse
clause runs if the loop completes successfully. So, you skip it by doingbreak
(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-loopsNonetheless I'd find the proposed syntax useful especially in a
grep
context:Which is shorter and easier to read than:
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?
Mithaldu, while you are technically correct (the best kind of correct!) I personally find the foreach spelling of for to be a lot more intuitive because it's more like natural language. And to me, fewer characters is never more important than better clarity.
Pawel, in your for loop example, the else clause would not be executed because the loop was executed at least once (it had to be entered in order to get to the last). In your while example, the else clause would be executed, because the loop body was never entered. I hope that is clear from my description.
Any language feature can be abused and sure, you could use this to create confusing and nonintuitive code. You can also write whole scripts that executed in the evaluation part of s///e, but that doesn't mean you should. To your specific point regarding goto I think this idea is a lot different from goto because it CANNOT be used to jump around arbitrarily, or into or out of a block. It is very limited in scope.
It does affect the code after the block, so I can see an argument that it is "spooky action at a distance" but I think it's pretty intuitive what's going on... really it's just syntactic sugar for
$loop_entered = 0;
foreach $item (@list) {
$loop_entered = 1;
loop body
}
if (not $loop_entered) {
else clause
}
As to your point that else is a Boolean term, well, that's what's happening. Either the loop happened or else invoke this code. If you are more concerned about overuse of a keyword, then what do you think would be a better keyword to use? How about "skipped?"
preaction, while googling around to see if any other languages have this feature, I encountered the else clause on loops in Python. I was really boggled... it seems like it's invoked in the exact opposite of circumstances when a loop's "else" clause should be.
I agree this would be very useful when paired with grep (or map)
Grinnz, I think the functionality of the continue block would be unaffected. It is executed after each iteration of the loop body, so if the loop block is executed at least once, the continue block is executed at least once (and the else block is skipped), and if the loop body is never executed, the continue block is never executed (and the else block is executed).
That said, are both of the following allowed? Is there a difference in execution between them? Is the second nonsensical and should be disallowed?
while ($condition) {
loop body
}
continue {
continue block
}
else {
else block
}
vs.
while ($condition) {
loop body
}
else {
else block
}
continue {
continue block
}