Exiting given via next

S

skendric

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
 
J

John W. Krahn

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
 
S

sln

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 = said:
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
 
U

Uri Guttman

M> His:

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
 
S

skendric

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
 
S

skendric

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

--sk
 
U

Uri Guttman

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
 
S

sln

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
 
S

sln

[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
 
S

sln

"s" == skendric <[email protected]> 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
 
S

skendric

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
 
U

Uri Guttman

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
 
S

sln

~% 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; }
}
}'
 
S

sln

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
 
S

skendric

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
 

Ask a Question

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

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,768
Messages
2,569,574
Members
45,050
Latest member
AngelS122

Latest Threads

Top