imperl has asked for the wisdom of the Perl Monks concerning the following question:

Hi Can I go from one point in the script to another using goto, if so how? Given below is a part of the script. For eg. if the conditions are true then I need to go to line 1. Any help would be appreciated. Thanks
print("Type R to re-enter the values or Type E to exit:\n"); $value=<STDIN> if ($value="R") { goto line 1 } elsif($value="E") { exit(); } else { print("Invalid entry, try again:\n"); goto line 1 } }
Thanks reasonablekeith!!

Edited by Arunbear: Changed title from 'Goto', as per Monastery guidelines

Replies are listed 'Best First'.
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.
      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.

      Cheers - L~R

      * Really there are 3, but 2 equate to the same thing.
      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; }
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.
      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";
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\

      while ( while not defined $value or $value eq 'R' )
      do you need the second 'while' in here?

        Er no it was a typo - I have removed it now.

        /J\

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.

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?"

      You can also use next and last (which are synonymous in a bare-block)...

      ...except for the way they handle continue blocks:

      use strict; use warnings; { next; } continue { print "this prints...\n"; } { last; } continue { print "...but this doesn't\n"; } __END__ this prints...

      the lowliest monk