My version of the loop doesn't use goto
No, it uses redo and next, which can be worse than goto. q-: (Except perhaps from the perspective of the optimizer which doesn't bother to try to figure out goto most of the time.)
But what I'm really puzzled about is this new "naked block with lots of redo, next, and last" that I've been seeing lately. This example doesn't require anything so powerful and easy-to-abuse as that. Why not some simple loops like:
local $_;
do {
do {
print "> ";
chomp( $_= <STDIN> );
} until( /\S/ );
} until( 'FALSE' eq cmd_select( split ' ' ) );
or
local $_;
do {
print "> ";
chomp( $_= <STDIN> );
} until( /\S/ && 'FALSE' eq cmd_select( split ' ' ) );
or even have your code handle EOF on STDIN:
local $_;
do {
do {
print "> ";
defined( $_= <STDIN> ) or die "EOF on STDIN";
chomp( $_ );
} until( /\S/ );
} until( 'FALSE' eq cmd_select( split ' ' ) );
(if you need to clean up on EOF, then throw this in a sub and return instead of die)
That way your code actually looks like "loop reading commands until you get a non-empty one and loop doing that until a 'quit' is requested". Not, "here is a block that I may or may not be using as a loop (please parse the rest of the block if you want to know), read a command, goto the top of the nearest surrounding loop (or naked block but not a conditional or do block) if the command is empty, otherwise go to the continue block (if there is one) or the top of the nearest surrounding loopish block, if a 'quit' was not requested". (:
I know that something like the following is a fairly common task:
lots of work to get next thing;
# possibly giving up for any of several reasons
goto TOP if thing isn't interesting;
if( thing is invalid ) {
instruct;
goto TOP;
}
do lots of stuff with thing;
goto TOP if not last thing;
if( no valid things found ) {
complain;
return;
}
finish up;
return result;
and that you can code that with a naked block and a few redos and/or nexts (which do the exact same thing in a naked block so mix them around to keep people guessing) and perhaps a last near the bottom. I mean you can do nearly anything with those almost like you can do anything with goto.
But I'd much rather stick to abusing the "early return" which I don't find hard to parse at all:
sub get_next_interesting_thing {
do {
return if ! get_next_thing;
} until( interesting_thing );
return thing;
}
sub get_next_valid_thing {
while( get_next_interesting_thing ) {
return thing if valid_thing;
instruct;
}
return;
}
if( ! get_next_valid_thing ) {
complain;
return;
}
do {
do lots of stuff with thing;
} while( get_next_valid_thing );
finish up;
return result;
(or if keeping track of having seen at least one valid thing is less work than retyping "get_next_valid_thing", then switch that bottom stuff around to look more like the original)
-
tye
(but my friends call me "Tye") |