Re: Advice on goto usage?
by Nevtlathiel (Friar) on May 05, 2005 at 09:08 UTC
|
Using goto is generally considered to be bad style as it can make your code hard to follow. Consider re-coding the above snippet without using a goto, eg:
#! /usr/bin/perl
use strict;
use warnings;
sub get_input {
print "Type R to re-enter the values or Type E to exit:\n";
chomp (my $value = <STDIN>);
$value;
}
my $value = get_input();
while ($value ne 'E') {
if ($value eq 'R') {
$value = get_input;
} else {
print 'Invalid entry, please try again\n';
get_input;
}
}
exit();
----------
My cow-orkers were talking in punctuation the other day. What disturbed me most was that I understood it.
| [reply] [d/l] [select] |
|
|
Nevtlathiel,
Using goto is generally considered to be bad style...
I agree with what you have said but feel it is important to share more of the story. There are 2* forms of goto in Perl and 1 isn't so bad at all. From TFM:
The "goto-&NAME" form is quite different from the other forms of "goto". In fact, it isn't a goto in the normal sense at all, and doesn't have the stigma associated with other gotos.
Read Pure Perl tail call optimization if you want to see how this is useful.
* Really there are 3, but 2 equate to the same thing.
| [reply] |
|
|
Was wondering, if anybody knows what wrong with this code. I want a certain set of batch files to be executed every 15 minutes for a period of 1 hour (or any number of hours inputed). I executed the script last evening and scheduled it for 2 hours but the script went on all night, for 15 hours. Any help would be appreciated.
$seconds=900/$num;
print "Enter the total period in hours:\n";
$periodhr=<STDIN>;
$periodsec=$periodhr*3600;
$output=1;
for($p=0; $p<=$periodmin; $p++)
{
for ($i=$f;$i<=$l; $i++)
{
$x="$t$i"; chomp($x);
$file="$x.bat"; chomp($file);
unless (-x $file) #-x here checks to see if the f
+ile is executable
{
warn "File $file does not appear to exist or is n
+ot executable!!\n";
next();
}
system("$file");
$time=localtime;
print FOUT "$output \t";
print FOUT "$file \t";
print FOUT "$time\n";
$output++;
sleep($seconds);
}
sleep($seconds);
$i=$f;
}
| [reply] [d/l] |
Re: Advice on goto usage?
by reasonablekeith (Deacon) on May 05, 2005 at 08:52 UTC
|
you need to use labels...
my $count = 0;
LOOP: print "help\n";
$count++;
die if $count > 10;
goto LOOP;
You should note, however, that gotos are considered bad practice, and quite rightly so in my opinion. Programs can be hard enough to follow when they flow logically, but with goto’s you can arbitrarily jump between any part of your program, quickly making a spaghetti nightmare, don’t be tempted unless your program is shorter than my example here. | [reply] [d/l] |
|
|
I'm not sure exactly how you wanted your script to work, but here's my attempt at a more structured version of your code.
Take notice that I've use 'eq' instead of '=' when comparing the values. '=' is the assignment operator, it doesn't compare two strings. Don't feel bad though, it's one of the biggest gotchas, and _everybody_ has done it at some point.
You also need to chomp the value from STDIN, as this will always have a new line ('\n') char at the end, and comparing $string eq "whatever" won't work because of the extra character
print("Type R to re-enter the values or Type E to exit:\n");
my @values;
while (<STDIN>) {
my $value = $_;
chomp($value);
last if $value eq 'E';
if ($value eq 'R') {
@values = ();
print "values have been cleared\n";
} else {
push(@values, $value);
}
}
print join(',', @values) . "\n";
| [reply] [d/l] |
Re: Advice on goto usage?
by gellyfish (Monsignor) on May 05, 2005 at 09:07 UTC
|
You want to avoid goto for this kind of thing - you are better off using a conditional looping construct:
#!/usr/bin/perl -w
#
+
use strict;
+
my $value;
+
while ( not defined $value or $value eq 'R' )
{
chomp($value = <STDIN>)
+
if ( $value eq 'E')
{
exit;
}
}
update: removed the extraneous while
/J\ | [reply] [d/l] [select] |
|
|
while ( while not defined $value or $value eq 'R' )
do you need the second 'while' in here?
| [reply] [d/l] |
|
|
| [reply] |
Re: Advice on goto usage?
by blazar (Canon) on May 05, 2005 at 08:58 UTC
|
It has already been pointed out, but it is important enough to be stressed: it is possible, but by all means do not do so. Not to say that there can't be situations in which it would be desirable or convenient to do so. Only I, for one, never found one (in Perl, that is). Well, actually once I thought I found one. But soon after I realised I was wrong.
I'm speaking of "real" goto's here, not about magic one, which is not really a goto, after all. | [reply] [d/l] [select] |
Re: Advice on goto usage?
by dragonchild (Archbishop) on May 05, 2005 at 13:30 UTC
|
No-one else seems to have pointed out the idiom for this:
INPUT: {
print("Type R to re-enter the values or Type E to exit:\n");
chomp( my $value = <STDIN> );
if ( $value eq 'E' ) {
exit;
}
if ( $value ne 'R' ) {
print("Invalid entry, try again:\n");
}
redo INPUT;
}
This is a bare-block with redo. You can also use next and last (which are synonymous in a bare-block) to leave the block and continue processing at the first line after the block. This is not considered 'goto' because redo/next/last are forced to work within either the innermost loop/bare block or with labelled loop/bare blocks. You can't redo to a labelled line, like you can with goto.
- In general, if you think something isn't in Perl, try it out, because it usually is. :-)
- "What is the sound of Perl? Is it not the sound of a wall that people have stopped banging their heads against?"
| [reply] [d/l] |
|
|
use strict;
use warnings;
{
next;
}
continue {
print "this prints...\n";
}
{
last;
}
continue {
print "...but this doesn't\n";
}
__END__
this prints...
| [reply] [d/l] |