Beefy Boxes and Bandwidth Generously Provided by pair Networks
XP is just a number
 
PerlMonks  

Exiting subroutine via next (that old chestnut)

by why_bird (Pilgrim)
on Mar 04, 2008 at 16:52 UTC ( [id://671926]=perlquestion: print w/replies, xml ) Need Help??

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

Hi all

This post is vaguely relevant to what I want to ask. As far as I can tell, the problem with exiting from a sub via next is that it performs the next iteration of any loop from within which it was called. However, that's the intention of my subroutine:

use strict; use warnings; sub RemoveComments { my $line=$_[0]; if ($$line =~ /#/){ $$line =~ s/#.*$//; } if ($$line =~ /^\s*$/){ next; } } .... while ($temp=<INPUT>){ &RemoveComments(\$temp); ... some other code ... }

This seems to happily remove commented lines from the file I'm reading in (assuming comments are perl like) and then throws away the line if the whole line is empty (i.e. comments at the start of a line, or competely blank lines) by calling the next iteration of the while $temp=<INPUT> loop. Otherwise it passes the de-commented line through the rest of the script.

However, although it appears to work happily, it throws an Exiting subroutine via next at xxx.pm line yy, <INPUT> line zz. error (and there's quite a lot of those so it's quite annoying!)

The only other way I could see to do it would be to get &RemoveComments() to return a variable, say '$empty', and then have the main code evaluate this and decide whether to do a 'next' or not:

use strict; use warnings; sub RemoveComments { my $line=$_[0]; if ($$line =~ /#/){ $$line =~ s/#.*$//; } if ($$line =~ /^\s*$/){ return 1; } } .... while ($temp=<INPUT>){ my $empty =0; $empty=&RemoveComments(\$temp); if ($empty == 1){ next; } ... some other code ... }

which just seems more messy to me, and more annoying to have to write an extra if(){} in every place that I just had to write &RemoveComments before. a)are my statements correct and/or b) am I missing a better way to do this or c) is my code happily working away nicely by accident..?

thanks :)
........
Those are my principles. If you don't like them I have others.
-- Groucho Marx
.......

Replies are listed 'Best First'.
Re: Exiting subroutine via next (that old chestnut)
by Roy Johnson (Monsignor) on Mar 04, 2008 at 17:13 UTC
    The test for empty line has nothing to do with removing comments, so there's no need to check for it in the sub. I'd reverse the test and do away with the next:
    sub RemoveComments { my $line=$_[0]; $$line =~ s/#.*$//; # No need for a separate pattern match } .... while ($temp=<INPUT>){ RemoveComments(\$temp); if ($temp =~ /\S/){ ... some other code ... } }
    but you could also do
    while ($temp=<INPUT>){ RemoveComments(\$temp); next if ($temp !~ /\S/); ... some other code ... }

    Caution: Contents may have been coded under pressure.
      Thanks all, I'll change it, even if I don't like it as much. I can probably live with one or two more lines of code. I suppose there is a good reason for it throwing a warning at me.. *sigh* :)
      ........
      Those are my principles. If you don't like them I have others.
      -- Groucho Marx
      .......
        Thanks all, I'll change it, even if I don't like it as much. I can probably live with one or two more lines of code. I suppose there is a good reason for it throwing a warning at me.. *sigh* :)
        It's good practice to never alter the control of a loop externally like that--it makes your subroutine very tightly coupled to that one specific usage, and in fact will blow things up if used differently. Functions should make it easier for you to reuse code in multiple contexts; it's one of their main reasons for existing. Most languages wouldn't even let you put a loop control variable in a sub like that (I know that's not entirely relevant, but just FYI) and Perl is reluctant to do so as well. Other people who may see your code in the future won't be expecting behavior like that.

        I think the first reply's solution, using and, is an elegant alternative, and makes it possible to tell what is going on just by looking at the loop code.

        My 2 cents!
Re: Exiting subroutine via next (that old chestnut)
by rhesa (Vicar) on Mar 04, 2008 at 16:59 UTC
    I'd suggest:
    RemoveComments(\$temp) and next;
      What does the 'and' do? (Googling for "perl 'and'" or "perlsyn 'and'" doesn't give much usefullness :P) I would have thought that that would just throw away every line of my file..?
      ........
      Those are my principles. If you don't like them I have others.
      -- Groucho Marx
      .......
        'and' is an operator. The idea would be to return a true value from your subroutine if you want to skip that line, and a false value otherwise.
Re: Exiting subroutine via next (that old chestnut)
by shmem (Chancellor) on Mar 04, 2008 at 17:07 UTC
    It is not an error, but a warning, and rightly so.

    If you ever call that sub only from within a loop, all is fine. But if you call it with no loop around, perl dies because next has no target.

    --shmem

    _($_=" "x(1<<5)."?\n".q·/)Oo.  G°\        /
                                  /\_¯/(q    /
    ----------------------------  \__(m.====·.(_("always off the crowd"))."·
    ");sub _{s./.($e="'Itrs `mnsgdq Gdbj O`qkdq")=~y/"-y/#-z/;$e.e && print}

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://671926]
Approved by Corion
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others having a coffee break in the Monastery: (4)
As of 2024-04-19 21:23 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found