Re: given/when one case prefixes another
by davido (Cardinal) on Apr 26, 2011 at 07:00 UTC
|
| [reply] [d/l] |
Re: given/when one case prefixes another
by AnomalousMonk (Archbishop) on Apr 26, 2011 at 08:36 UTC
|
This works in Strawberry 5.10.1.4, but I don't know how 'proper' it is; frankly, it looks a bit hinky to me.
>perl -wMstrict -lE
"for my $s qw(a b c d) {
given ($s) {
when ('a') { say 'a'; continue; }
when ('b') { say 'b'; continue; }
when (/[ab]/) { say ' after a or b'; }
say 'neither a nor b';
when ('d') { say 'd'; }
default { say qq{other: '$_'}; }
}
}
"
a
after a or b
b
after a or b
neither a nor b
other: 'c'
neither a nor b
d
BTW: I couldn't get the goto approach to work: Perl experiences a 'panic: goto' attack.
| [reply] [d/l] [select] |
|
|
It seems like perfectly fine code to me.
I guess you are wondering if the code directly in "given" (without a "when" clause) is "proper". The answer is yes. That's one feature that distinguishes given/when from the switch statement in C.
But do consider that such code could become hard to read if the whole given/when doesn't fit onto one or two screen pages anymore - you shouldn't be doing very much in the when clauses (calling functions or methods should be fine).
| [reply] |
|
|
I suppose I was uneasy about the possibility of the when (/[ab]/) { ... } tail clause 'getting lost', dependent as it is on a continue statement in other, possibly distant, clauses, and on the relative positions of those clauses (also a dependency of Neighbour's approach). Taking apl's suggestion, I am more comfortable with something like the following, which encapsulates the tail of each 'tailed' clause within the clause itself:
>perl -wMstrict -lE
"for my $s qw(a b c d) {
given ($s) {
my $tail_a_and_b = sub { say qq{ after a or b, was '$_' } };
when ('a') { say 'a'; $tail_a_and_b->(); }
when ('b') { say 'b'; $tail_a_and_b->(); }
when ('d') { say 'd'; }
default { say qq{other: '$_'}; }
}
}
"
a
after a or b, was 'a'
b
after a or b, was 'b'
other: 'c'
d
| [reply] [d/l] [select] |
Re: given/when one case prefixes another
by ikegami (Patriarch) on Apr 26, 2011 at 06:53 UTC
|
If you want to continue into the next block, you can use continue. If you want to go to some other block, you can use goto, although jumping into another block is deprecated. | [reply] [d/l] [select] |
|
|
| [reply] |
|
|
Oops on continue. Iw as going by the docs, and they aren't clear in that area, so I naturally assumed C-like behaviour.
Labeling the outside of a block statement is easy and legal.
FOO: {
...
}
| [reply] [d/l] [select] |
Re: given/when one case prefixes another
by Neighbour (Friar) on Apr 26, 2011 at 08:12 UTC
|
You could modify $_ inside the given-when scope to some magic value indicating the common ending code needs to be executed. Like so:
#!/usr/bin/perl
use warnings;
use strict;
use v5.10;
my @data = ('foo', 'bar', 'baz');
for my $element (@data) {
given ($element) {
when ('foo') {
# Do foo things
print("foo here\n");
# force common ending routine
$_ = 'MAGIC_foobar';
continue;
}
when ('bar') {
# Do bar things
print("bar here\n");
# force common ending routine
$_ = 'MAGIC_foobar';
continue;
}
when ('baz') {
# Do baz things
print("baz here\n");
}
when ('MAGIC_foobar') {
# Do common ending things here
print("foobar ending here\n");
}
}
}
This produces the following output:
foo here
foobar ending here
bar here
foobar ending here
baz here
| [reply] [d/l] [select] |
|
|
Ah, so continue means "keep checking for more matches"? The docs, like the previous poster, said it falls through to the next case. That's not at all the same thing!
| [reply] |
|
|
Maybe "not the same thing" but definitely not "'keep checking for more matches'" (within the current when, anyway).
At least, not in the same sense as the /g modifier in a regex. Observe:
#!/usr/bin/perl
use strict;
use warnings;
use 5.012;
# 901284
my $count=0;
my $foo = "X x y y x y Z";
say "First, with a simple substitution '/g'";
my $simplecount = $foo =~ s/x/o/g;
say " \$foo: $foo; \n \$simplecount: $simplecount (i.e., 'x's changed)
+";
$foo =~ s/o/x/g;
say "\$foo restored: $foo \n";
say 'Now, with given/when and =~ /x/g';
given( $foo ) {
when ( $foo =~ /x/g ) {
say "\$foo contains an x";
$count++;
say "\$foo: $foo; \n \$count: $count;";
continue
}
when ( /y/ ) {
say "\n \$foo contains a y";
}
default {
say "$foo does not contain a y";
}
}
say "\n Final \$count of 'x' in given/when matching 'x': $count";
say "\n $foo";
OUTPUT:
First, with a simple substitution '/g'
$foo: X o y y o y Z;
$simplecount: 2 (i.e., 'x's changed)
$foo restored: X x y y x y Z
Now, with given/when and =~ /x/g
$foo contains an x
$foo: X x y y x y Z;
$count: 1;
$foo contains a y
Final $count of 'x' in given/when matching 'x': 1
X x y y x y Z
One possible reading is that continue's precedence terminates the matching. Perhaps a wiser head will explain (and correct, as necessary).
Update: typo fixed (from /s/g to /x/g) at line 15 and in the output. Gnahh!
| [reply] [d/l] [select] |
Re: given/when one case prefixes another
by LanX (Saint) on Apr 26, 2011 at 10:15 UTC
|
| [reply] [d/l] [select] |
|
|
Good point about mixing if/when. I'm still not used to it enough to use it to its full ability.
| [reply] |
Re: given/when one case prefixes another
by apl (Monsignor) on Apr 26, 2011 at 10:31 UTC
|
I have several cases that end the same way.
Turn the same way into a procedure, and refactor your code...
| [reply] |
|
|
| [reply] |
|
|
> The short amount of code and large about of local variables involved makes that awkward.
why?
for ( 1..2,"a".."b") {
ifnum();
ifchar();
print "\n"
}
sub ifnum {
if (/1/) { print }
elsif (/2/) { print }
else { return }
print " is number";
}
sub ifchar {
print && goto CONT if /a/;
print && goto CONT if /b/;
return;
CONT:
print " is character";
}
OUTPUT:
1 is number
2 is number
a is character
b is character
UPDATE: changed ifnum() to elsif-clauses.
see also: Re: given/when one case prefixes another | [reply] [d/l] [select] |
Re: given/when one case prefixes another
by LanX (Saint) on Apr 26, 2011 at 22:07 UTC
|
for ("a".."c"){
{
print && next if /a/;
print && next if /b/;
# here neither a nor b
last; # skip continue-block
} continue {
# here either a or b
print " is in group1";
}
print "\n" # all
}
your free to have more blocks or combining with elseifs or LABEL:s.
UPDATE:
or without fall-through
for ("a".."c"){
{
if ( /a/ ) { print }
elsif ( /b/ ) { print }
else { last }
print " is in group"; # a,b
}
print "\n" # all
}
See also: Re^3: given/when one case prefixes another | [reply] [d/l] [select] |
|
|
I see: there are advantages to using if statements instead of when's. I'll keep that in mind.
| [reply] |