Exiting given via next

Discussion in 'Perl Misc' started by skendric@fhcrc.org, Apr 22, 2009.

  1. Guest

    i'm fond of constructs like the following:

    use Switch;
    LINE:
    while (my $line = <$fh>) {
    switch ($line) {
    case /Shrill and clear he crowed/ {
    say 'shrill';
    $count++;
    next LINE;
    }
    case /Recking nothing of wizardry/ {
    say 'recking';
    $count++;
    next LINE;
    }
    else {
    next LINE;
    }
    }
    }

    but, switch has a memory leak (http://rt.cpan.org/Public/Bug/
    Display.html?id=45232), which makes it unsuitable for sitting inside
    loops which iterate many times

    the new switch statement in perl-5.10.0 does not have this memory
    leak:

    use feature 'switch';
    LINE:
    given ($line) {
    when (/Shrill and clear he crowed/) {
    say 'shrill';
    $count++;
    next LINE;
    }
    when (/Recking nothing of wizardry/) {
    say 'recking';
    $count++;
    next LINE;
    }
    default {
    next LINE;
    }
    }

    however, the 'switch' feature doesn't like seeing 'next':

    gnat> ./daily-syslog-extracts
    Parsing logfile...
    Exiting when via next at ./daily-syslog-extracts line 179, <GEN0> line
    7.
    Exiting given via next at ./daily-syslog-extracts line 179, <GEN0>
    line 7.
    Exiting when via next at ./daily-syslog-extracts line 179, <GEN0> line
    12.
    Exiting given via next at ./daily-syslog-extracts line 179, <GEN0>
    line 12.
    [...]


    is there some way to persuade the new 'switch' feature to tolerate
    'next' statements? or at least to be quiet about its displeasure?

    [i can fall back to a cascaded if/elsif structure ... but i find
    'switch' cleaner to read, so much so that i'm having trouble letting
    go of it]

    --sk

    stuart kendrick
    fhcrc
    , Apr 22, 2009
    #1
    1. Advertising

  2. wrote:
    > i'm fond of constructs like the following:
    >
    > use Switch;
    > LINE:
    > while (my $line = <$fh>) {
    > switch ($line) {
    > case /Shrill and clear he crowed/ {
    > say 'shrill';
    > $count++;
    > next LINE;
    > }
    > case /Recking nothing of wizardry/ {
    > say 'recking';
    > $count++;
    > next LINE;
    > }
    > else {
    > next LINE;
    > }
    > }
    > }
    >
    > but, switch has a memory leak (http://rt.cpan.org/Public/Bug/
    > Display.html?id=45232), which makes it unsuitable for sitting inside
    > loops which iterate many times
    >
    > the new switch statement in perl-5.10.0 does not have this memory
    > leak:
    >
    > use feature 'switch';
    > LINE:
    > given ($line) {
    > when (/Shrill and clear he crowed/) {
    > say 'shrill';
    > $count++;
    > next LINE;
    > }
    > when (/Recking nothing of wizardry/) {
    > say 'recking';
    > $count++;
    > next LINE;
    > }
    > default {
    > next LINE;
    > }
    > }
    >
    > however, the 'switch' feature doesn't like seeing 'next':
    >
    > gnat> ./daily-syslog-extracts
    > Parsing logfile...
    > Exiting when via next at ./daily-syslog-extracts line 179, <GEN0> line
    > 7.
    > Exiting given via next at ./daily-syslog-extracts line 179, <GEN0>
    > line 7.
    > Exiting when via next at ./daily-syslog-extracts line 179, <GEN0> line
    > 12.
    > Exiting given via next at ./daily-syslog-extracts line 179, <GEN0>
    > line 12.
    > [...]
    >
    >
    > is there some way to persuade the new 'switch' feature to tolerate
    > 'next' statements? or at least to be quiet about its displeasure?
    >
    > [i can fall back to a cascaded if/elsif structure ... but i find
    > 'switch' cleaner to read, so much so that i'm having trouble letting
    > go of it]


    given/when/default is not a loop construct, just as if/unless/elsif/else
    is not. next/last/redo will only work properly from inside a loop.
    Perhaps you want to use *goto* instead?



    John
    --
    Those people who think they know everything are a great
    annoyance to those of us who do. -- Isaac Asimov
    John W. Krahn, Apr 23, 2009
    #2
    1. Advertising

  3. Guest

    On Wed, 22 Apr 2009 15:49:43 -0700 (PDT), wrote:

    >i'm fond of constructs like the following:
    >
    >use Switch;
    >LINE:
    >while (my $line = <$fh>) {
    > switch ($line) {
    > case /Shrill and clear he crowed/ {
    > say 'shrill';
    > $count++;
    > next LINE;
    > }
    > case /Recking nothing of wizardry/ {
    > say 'recking';
    > $count++;
    > next LINE;
    > }
    > else {
    > next LINE;
    > }
    > }
    >}
    >
    >but, switch has a memory leak (http://rt.cpan.org/Public/Bug/
    >Display.html?id=45232), which makes it unsuitable for sitting inside
    >loops which iterate many times
    >
    >the new switch statement in perl-5.10.0 does not have this memory
    >leak:
    >
    >use feature 'switch';
    >LINE:


    while (my $line = <$fh>) {

    >given ($line) {
    > when (/Shrill and clear he crowed/) {
    > say 'shrill';
    > $count++;
    > next LINE;
    > }


    I don't have 5.10 , does given() replace the
    while ($line = <$fh>) {
    ?
    Otherwise, it might be infinite loop thing.

    -sln
    , Apr 23, 2009
    #3
  4. Uri Guttman Guest

    >>>>> "M" == Mark <> writes:

    M> His:

    >>> while (my $line = <$fh>) {


    M> IS a loop; a simple 'next;' (not 'next LINE;' per se) should be enough
    M> to get the outer ''while' loop going (if the condition is still true, of
    M> course).

    but that was using the Switch module (which is evil since it does source
    filtering). his second case using the 5.10 switch feature (built in and
    not a source filter) didn't have a loop. he was wondering why next
    didn't work inside the given. the answer (which is correct) is that
    given is not a loop construct. if it was wrapped in a while as in the
    first example, next would work.

    > use feature 'switch';
    > LINE:
    > given ($line) {
    > when (/Shrill and clear he crowed/) {


    uri

    --
    Uri Guttman ------ -------- http://www.sysarch.com --
    ----- Perl Code Review , Architecture, Development, Training, Support ------
    --------- Free Perl Training --- http://perlhunter.com/college.html ---------
    --------- Gourmet Hot Cocoa Mix ---- http://bestfriendscocoa.com ---------
    Uri Guttman, Apr 23, 2009
    #4
  5. Guest

    hi uri,

    i was being too terse ... in fact, the second case is the same as the
    first (wrapped in a while loop) ... is there some way to suppress the
    'Exiting via given/when' complaints?

    use feature 'switch';
    while (my $line = <$fh>) {
    LINE:
    given ($line) {
    when (/Shrill and clear he crowed/) {
    say 'shrill';
    $count++;
    next LINE;
    }
    when (/Recking nothing of wizardry/) {
    say 'recking';
    $count++;
    next LINE;
    }
    default {
    next LINE;
    }
    }
    }

    --sk

    > but that was using the Switch module (which is evil since it does source
    > filtering). his second case using the 5.10 switch feature (built in and
    > not a source filter) didn't have a loop. he was wondering why next
    > didn't work inside the given. the answer (which is correct) is that
    > given is not a loop construct. if it was wrapped in a while as in the
    > first example, next would work.
    , Apr 23, 2009
    #5
  6. Guest

    or am i doing something evil by trying to exit given and when clauses
    using 'next'?

    --sk
    , Apr 23, 2009
    #6
  7. Uri Guttman Guest

    >>>>> "s" == skendric <> writes:

    s> i was being too terse ... in fact, the second case is the same as the
    s> first (wrapped in a while loop) ... is there some way to suppress the
    s> 'Exiting via given/when' complaints?

    you have several mistakes and easy ways to fix this.

    s> use feature 'switch';
    s> while (my $line = <$fh>) {
    s> LINE:

    that label should be before the while. but that isn't the main bug.

    s> given ($line) {
    s> when (/Shrill and clear he crowed/) {
    s> say 'shrill';
    s> $count++;
    s> next LINE;


    from perldoc perlsyn:

    Breaking out

    You can use the "break" keyword to break out of the enclosing "given"
    block. Every "when" block is implicitly ended with a "break".


    but since you will exit the given block anyway in all cases, just fall
    through and you will do the loop anyway. there is no need for the next
    calls. i tested that. about the only time you will need to break from a
    given is when you have to deeper inside a when clause.

    s> }
    s> when (/Recking nothing of wizardry/) {
    s> say 'recking';
    s> $count++;
    s> next LINE;

    delete that (and the previous) next and it works fine and quietly.

    s> }
    s> default {
    s> next LINE;
    s> }

    that whole default clause isn't needed. you will exit the given block if
    nothing is matched by a when and then you will loop as expected.

    you need to read up more about given/when and see how it works by
    default. you were trying too hard to exit when it exits for you!

    uri

    --
    Uri Guttman ------ -------- http://www.sysarch.com --
    ----- Perl Code Review , Architecture, Development, Training, Support ------
    --------- Free Perl Training --- http://perlhunter.com/college.html ---------
    --------- Gourmet Hot Cocoa Mix ---- http://bestfriendscocoa.com ---------
    Uri Guttman, Apr 23, 2009
    #7
  8. Guest

    On Thu, 23 Apr 2009 06:22:25 -0700 (PDT), wrote:

    >hi uri,
    >
    >i was being too terse ... in fact, the second case is the same as the
    >first (wrapped in a while loop) ... is there some way to suppress the
    >'Exiting via given/when' complaints?
    >
    >use feature 'switch';
    >while (my $line = <$fh>) {
    > LINE:
    > given ($line) {
    > when (/Shrill and clear he crowed/) {
    > say 'shrill';
    > $count++;
    > next LINE;
    > }


    With 5.8.6 I get "Label not found..." with your block structure.
    while (my $line = <DATA>)
    {
    LABEL:
    @ar = map {
    next LABEL if (++$i > 10); $_
    } split (//, $line);
    print "$i";
    getc(STDIN);
    next;
    }
    print "end\n";

    But with label up here, I don't get that error.
    LABEL:
    while (my $line = <DATA>)
    {
    LABEL:
    @ar = map {
    ...

    -sln
    , Apr 23, 2009
    #8
  9. Guest

    On Thu, 23 Apr 2009 11:14:17 -0400, Uri Guttman <> wrote:

    >>>>>> "s" == skendric <> writes:

    >

    [snip]
    >from perldoc perlsyn:
    >
    > Breaking out
    >
    > You can use the "break" keyword to break out of the enclosing "given"
    > block. Every "when" block is implicitly ended with a "break".
    >
    >
    >but since you will exit the given block anyway in all cases, just fall
    >through and you will do the loop anyway. there is no need for the next
    >calls.


    Unfortunately, you have to specify "continue" inside a when() to "fall through" to the next
    when block, otherwise a "break" is implicit from a given(), like what you said, or a "next"
    is implicit if the given is called from a loop block.

    This is opposite of how the C switch/case works. There is no implicit "break" within a case block,
    only fall through behavior, to the next case. A break is explicit from the switch.
    In Perl now, to fall through, you have to explicitly continue, otherwise the break is implicit.

    More confusion.

    -sln
    , Apr 23, 2009
    #9
  10. Guest

    On Thu, 23 Apr 2009 09:18:29 -0700, wrote:

    >On Thu, 23 Apr 2009 11:14:17 -0400, Uri Guttman <> wrote:
    >
    >>>>>>> "s" == skendric <> writes:

    >>

    >[snip]
    >>from perldoc perlsyn:
    >>
    >> Breaking out
    >>
    >> You can use the "break" keyword to break out of the enclosing "given"
    >> block. Every "when" block is implicitly ended with a "break".
    >>
    >>
    >>but since you will exit the given block anyway in all cases, just fall
    >>through and you will do the loop anyway. there is no need for the next
    >>calls.

    >
    >Unfortunately, you have to specify "continue" inside a when() to "fall through" to the next
    >when block, otherwise a "break" is implicit from a given(), like what you said, or a "next"
    >is implicit if the given is called from a loop block.

    ^^^^^
    when
    >
    >This is opposite of how the C switch/case works. There is no implicit "break" within a case block,
    >only fall through behavior, to the next case. A break is explicit from the switch.
    >In Perl now, to fall through, you have to explicitly continue, otherwise the break is implicit.
    >
    >More confusion.
    >
    >-sln
    , Apr 23, 2009
    #10
  11. Guest

    ok, i've made a classic error here: i over-simplified

    here's something a little closer to what i want to do (not guaranteed
    to work; i'm trying to stay conceptual here. conceptually, i'm
    filtering a log file ... some lines are interesting, some are not, and
    i'm taking a tiered approach to skipping the uninteresting lines,
    throwing some away immediately, tossing others only after more
    detailed inspection)

    use feature 'switch;'
    use List::MoreUtils qw(any);
    [...]
    LINE:
    while (my $line = <$fh>) {
    next LINE if $line =~ /various patterns/; # Skip obviously
    uninteresting lines

    # This line might be interesting; if it is, save it; otherwise, skip
    to the next line
    given ($line) {
    when /\-fw/ { # Firewalls
    next LINE if any { $line =~ /$_/ } @{$ignore{'Firewall'}}; #
    Actually, not interesting
    push @{$keep{'Firewall'}}, $line;
    }
    when /\-rtr/ { # Routers
    next LINE if any { $line =~ /$_/ } @{$ignore{'Firewall'}}; #
    Actually, not interesting
    push @{$keep{'Router'}}, $line;
    }
    [...]
    default {
    next LINE; # Turns out that this line isn't interesting after
    all, skip to the next one
    }
    }

    # OK, if I've made it this far, this line is interesting to me in
    various ways
    # Do more processing here
    [...]

    }


    so, if i use 'break', then i escape the 'when' stanza, fall through to
    the end of the 'given' ... but i don't want to fall through to the end
    of 'given': i don't want to reach the 'Do more processing here'
    section, because i've determined that this line isn't interesting
    after all

    (a) i could replace 'next LINE' with 'break' and then stuff all my 'do
    more processing' code into a subroutine and call it from each and
    every 'when' clause. repetitious, but it would work

    (b) i could go back to using cascaded if/elsif

    (c) i could refactor my approach entirely ...

    but here's my specific question: what is it about the perl-5.10.0
    switch construct (what is it about 'given/when') that makes the use of
    'next' worthy of the 'Exitting given via next' warning?

    --sk

    stuart kendrick
    fhcrc
    , Apr 23, 2009
    #11
  12. Uri Guttman Guest

    >>>>> "s" == skendric <> writes:
    s> LINE:
    s> while (my $line = <$fh>) {
    s> next LINE if $line =~ /various patterns/; # Skip obviously
    s> uninteresting lines


    as i said before, there is no need for the label and LINE, plain next
    should work. and my test showed that there is no warning if the given
    block is inside the while. loop labels are needed if you are breaking
    out of nested loops from deeper inside.

    s> (a) i could replace 'next LINE' with 'break' and then stuff all my 'do
    s> more processing' code into a subroutine and call it from each and
    s> every 'when' clause. repetitious, but it would work

    s> (b) i could go back to using cascaded if/elsif

    this is fine for what you want. but there is no need for the elsif if
    you call next. that should clean it up a bit. you do need explicit use
    of $line instead of the cleaner when().

    s> (c) i could refactor my approach entirely ...

    that is another idea.

    s> but here's my specific question: what is it about the perl-5.10.0
    s> switch construct (what is it about 'given/when') that makes the use of
    s> 'next' worthy of the 'Exitting given via next' warning?

    well, given isn't a loop construct so breaking from it with next is
    'wrong' and should be warned. ben shows that it doesn't warn if there is
    no label used so that confuses it even more. i would skip the label as
    it isn't needed and it quiets the warning. this smells of a bug and
    should be reported to p5p.

    and in the worst case you could silence that particular warning with a
    no warnings statement with the right arg.

    uri

    --
    Uri Guttman ------ -------- http://www.sysarch.com --
    ----- Perl Code Review , Architecture, Development, Training, Support ------
    --------- Free Perl Training --- http://perlhunter.com/college.html ---------
    --------- Gourmet Hot Cocoa Mix ---- http://bestfriendscocoa.com ---------
    Uri Guttman, Apr 23, 2009
    #12
  13. Guest

    On Thu, 23 Apr 2009 17:25:47 +0100, Ben Morrow <> wrote:

    > ~% perl -wE'LINE: for my $x (1..3) {
    > say $x;
    > given ($x) {
    > when (1) { next LINE }
    > }
    > }'


    "Switching in a loop" http://perldoc.perl.org/perlsyn.html
    'Instead of using given() , you can use a foreach() loop'
    'On exit from the when block, there is an implicit next'
    ....
    'This doesn't work if you explicitly specify a loop variable,
    as in for $item (@array) . You have to use the default variable $_ .
    (You can use for my $_ (@array) .)'


    I don't have 5.10 but try this and see what happens. Also try it in a .pl script.
    If this craps out, then next LABEL is in doubt in given/when constructs.
    They need to debug this stuff, its not stable. Thats why I stayed with 5.8.x for
    a while longer.

    -sln

    ~% perl -wE'LINE: for (1..3) {
    say $_;
    when ($_ == 1) { next LINE; }
    }
    }'
    , Apr 23, 2009
    #13
  14. Guest

    On Thu, 23 Apr 2009 10:03:55 -0700 (PDT), wrote:

    >ok, i've made a classic error here: i over-simplified
    >
    >here's something a little closer to what i want to do (not guaranteed
    >to work; i'm trying to stay conceptual here. conceptually, i'm
    >filtering a log file ... some lines are interesting, some are not, and
    >i'm taking a tiered approach to skipping the uninteresting lines,
    >throwing some away immediately, tossing others only after more
    >detailed inspection)
    >
    >use feature 'switch;'
    >use List::MoreUtils qw(any);

    ^^^^
    seen it, never used it but get the jist in your usage below

    >[...]
    >LINE:
    >while (my $line = <$fh>) {
    > next LINE if $line =~ /various patterns/; # Skip obviously

    ^^^^
    But you should really just use next with no label for now until
    Perl gets its head out of its ...

    >uninteresting lines
    >
    > # This line might be interesting; if it is, save it; otherwise, skip
    >to the next line
    > given ($line) {
    > when /\-fw/ { # Firewalls

    ^
    Is this really necessary?

    > next LINE if any { $line =~ /$_/ } @{$ignore{'Firewall'}}; # Actually, not interesting

    ^^
    Be carefull here. given()'s default behavior is to asign $_ its simple parameter, you've just
    overwritten it. There are exceptions though. Check given/when at http://perldoc.perl.org/perlsyn.html.

    > push @{$keep{'Firewall'}}, $line;


    Now you are keeping $line and are breaking (by default) to the "OK, made it this far.." code, just past the
    given() block.
    > }
    > when /\-rtr/ { # Routers

    ^^^^
    when (/\-rtr/)
    I don't know this construct yet so I'd feel funny giving the parser a chance to screw up my intention's when
    I am debugging.
    Each encounter with an apparent '-' option appears to be unique per line, which seems kind of strange.
    Otherwise, with possible multiple options per line, you could have used the "fall through mechanism": continue statement,
    instead of the next LINE, thereby taking you to the default block which does the next line.
    If thats the case, and you have multiple options per line though, some options are interresting and some aren't,
    after a push but before a continue, $interresting |= (bit) will mitigate in the default block to bump the next line or continue
    processing in the "OK, made it this far.." code.

    > next LINE if any { $line =~ /$_/ } @{$ignore{'Firewall'}}; # Actually, not interesting
    > push @{$keep{'Router'}}, $line;


    Again, breaking to the "OK.." code.

    > }
    > [...]
    > default {
    > next LINE; # Turns out that this line isn't interesting after all, skip to the next one

    ^^^^
    next if !$interresting;

    Otherwise your breaking out of the given () block.
    Like mentioned, if multiple options per line, you are interrested here in one, some or all, depending on the
    $interresting bit map you set in the when() blocks. This would be checked in another given/when (or if/then construct)
    withing the "OK..." code path below.

    > }
    > }
    >
    > # OK, if I've made it this far, this line is interesting to me in various ways


    So, check the $interresting bit map to see what is of interrest, then act upon it.

    > # Do more processing here
    > [...]
    >
    >}


    -sln
    , Apr 23, 2009
    #14
  15. Guest

    ahh, ok. light bulbs.

    "Repetition is the key to learning". thank you for repeating the gist
    of what you were trying to convey, using different words

    i understand now and can see how to continue. thank you for your
    detailed assistance,

    --sk

    stuart kendrick
    fhcrc
    , Apr 24, 2009
    #15
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Lord0
    Replies:
    1
    Views:
    563
    Thomas Weidenfeller
    Apr 19, 2006
  2. Abby
    Replies:
    1
    Views:
    493
    Jack Klein
    Aug 29, 2003
  3. Deniz Bahar
    Replies:
    2
    Views:
    464
    Andrey Tarasevich
    Mar 9, 2005
  4. Karthi kn
    Replies:
    2
    Views:
    371
  5. Prince Al

    Exiting threads via signal

    Prince Al, Nov 11, 2009, in forum: Perl Misc
    Replies:
    6
    Views:
    134
    Wanna-Be Sys Admin
    Nov 12, 2009
Loading...

Share This Page