http://qs321.pair.com?node_id=346409

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

Dear monks:

I have the following pretty simple subroutine which finds and returns the next non-empty, non-comment line in an input text file. Comments are lines beginning with "#". dprint() is a printing sub for debugging.

sub nextline { my $fh = shift; my $l; do { $l = <$fh>; if (!defined($l)) { dprint "end of file\n"; return undef } dprint "line is: $l"; next if ($l =~ /^#/); # skip comments $l = clean($l); } until ($l ne ''); # skip blank lines return $l; } ## end sub nextline
This code works perfectly, but for every comment in the input file, Perl complains (even without strict):
Exiting subroutine via next...
What kind of trouble can doing it this way cause, or why is Perl complaining?

Thanks kindly,
Vacant

Replies are listed 'Best First'.
Re: exiting via next: Extra careful or just bitchy?
by Roy Johnson (Monsignor) on Apr 19, 2004 at 19:05 UTC
    perldoc -f do "do BLOCK" does *not* count as a loop, so the loop control statements "next", "last", or "redo" cannot be used to leave or restart the block. See perlsyn for alternative strategies.
    If you've got a loop in which you're calling nextline, your loop is going to restart every time sub hits that next. This code:
    for (10..13) { print "Top loop $_\n"; do_sub($_); print "-- after sub\n"; } sub do_sub { my ($a) = shift; do { next if $a < 15; print "Sub $a\n"; } while ($a < 20); }
    yields this output (notice neither the print in the sub nor the print 'after sub' lines ever execute):
    Top loop 10 Exiting subroutine via next at try2.pl line 14. Top loop 11 Exiting subroutine via next at try2.pl line 14. Top loop 12 Exiting subroutine via next at try2.pl line 14. Top loop 13 Exiting subroutine via next at try2.pl line 14.

    The PerlMonk tr/// Advocate
Re: exiting via next: Extra careful or just bitchy?
by saintmike (Vicar) on Apr 19, 2004 at 19:06 UTC
    From perldoc perlsyn:

    See "do" in perlfunc. Note also that the loop control statements described later will NOT work in this construct, because modifiers don't take loop labels. Sorry. You can always put another block inside of it (for "next") or around it (for "last") to do that sort of thing. For "next", just double the braces:

    do {{ next if $x == $y; # do something here }} until $x++ > $z;
Re: exiting via next: Extra careful or just bitchy?
by dug (Chaplain) on Apr 19, 2004 at 19:33 UTC
    My guess is that you have tailored your program to work with the logic in this subroutine (or that it's an accidental success).

    perldoc -f do says:
    "do BLOCK" does not count as a loop, so the loop control statements "next", "last", or "redo" cannot be used to leave or restart the block. See perlsyn for alternative strategies.
    More details are available in perlsyn

    One way what you've written would work could be described as:

    1) you repeatedly call my $line = nextline( $fh );
    2) the first line of the do block reads a line off of your filehandle.
    3 a) if that line is a comment, the subroutine exits via next (next doesn't go to the next iteration of the do block (as we learned from the documentation)).
    3 b) if that line isn't a comment, it's assigned to $l (via clean()).
    4) this happens until $l ne ''.

    Since even "blank" lines will contain a newline, the until conditional will guarantee that your do block is only entered once (even for non-comment lines).

    Hope that helps a little,

    -- Douglas
      Yes, I think that is exactly what was happening. (Was -- I have fixed it by now.) This sub is part of a simple parser, and the caller patiently ignored the empty strings and called the sub again. Your remark about the "blank" lines not being really empty is also well noted. Actually, the clean() sub removes the newlines, which I did not mention.
Re: exiting via next: Extra careful or just bitchy?
by allolex (Curate) on Apr 19, 2004 at 19:06 UTC

    next (perldoc -f next) is for skipping over a loop iteration. Since your subroutine does not appear to be a loop, you should probably use something like return (perldoc -f return) to exit the subroutine. Read the caveats in the documentation, though. ;)

    --
    Damon Allen Davison
    http://www.allolex.net

      Not exit! Maybe you mean return.

      The PerlMonk tr/// Advocate
        Not exit! Maybe you mean return.

        Indeed I did! And I typed the wrong one twice. I'll fix it now. Mysterious non-functioning code... ;)

        --
        Damon Allen Davison
        http://www.allolex.net

Re: exiting via next: Extra careful or just bitchy?
by CountZero (Bishop) on Apr 19, 2004 at 19:33 UTC
    What about:
    my $fh = DATA; while (<$fh>) { chomp; next if /^#/ or $_ eq ''; print $_; } __DATA__ Print this and this # but not this Print me # not OK
    One other remark: I'm not sure it is a good idea to do a "my $1". These variables have some magic in them which might get spoiled by doing that.

    CountZero

    "If you have four groups working on a compiler, you'll get a 4-pass compiler." - Conway's Law

Re: exiting via next: Extra careful or just bitchy?
by vacant (Pilgrim) on Apr 19, 2004 at 19:21 UTC
    Ok, i get it: "do BLOCK does not count as a loop" pretty much explains it. Thanks for the pointer. My large, heavy Perl books do not make this very clear.

      Try chanting what you want to memorize while bashing your head with them. This method helped me memorize lots of stuff in school... or was that college? (For some reason my memory isn't so good anymore.) ;)

      --
      Damon Allen Davison
      http://www.allolex.net