Re: Would you use a switch instead?
by Corion (Patriarch) on Jul 04, 2009 at 13:08 UTC
|
Perl has no switch statement. Maybe you mean a dispatch table, which I'd consider using, or a given statement, if you're using Perl 5.10 or higher.
| [reply] [d/l] [select] |
|
| [reply] |
Re: Would you use a switch instead?
by FunkyMonk (Chancellor) on Jul 04, 2009 at 13:34 UTC
|
There is the Switch module, but it's a source filter and considered evil. Perl 5.10 has the given/when statements, that are the equivalent of Switch.
If you're stuck on an earlier perl, you could also use something like:
for ($value) {
/aaa/ && do { $foo = 'wanna'; last };
/bbb/ && do { $foo = 'be'; last };
/ccc/ && do { $foo = 'startin'; last };
$foo = 'somethin';
}
Tested with dodgy eyes only! | [reply] [d/l] |
|
And, of course, foreach-loop topicalization can also be combined with the original nested ternary expression, although definition and initialization of the variable $foo are no longer so closely tied together:
>perl -wMstrict -le
"my $value = 'bbb';
my $foo;
for ($value) {
$foo = /aaa/ ? 'wanna'
: /bbb/ ? 'be'
: /ccc/ ? 'startin'
: 'somethin'
;
}
print $foo;
"
be
| [reply] [d/l] [select] |
|
| [reply] |
|
Re: Would you use a switch instead?
by eyepopslikeamosquito (Archbishop) on Jul 05, 2009 at 04:50 UTC
|
See Perl Best Practices:
items 6.15 (avoid cascading an if), 6.16 (use table look-up in preference to cascaded equality tests), and 6.17 (when producing a value, use tabular ternaries).
I'd say PBP would endorse your original "tabular ternary" solution, albeit
with a different layout style. PBP (item 6.17) compares:
my $salute;
if ($name eq $EMPTY_STR) {
$salute = 'Dear Customer';
}
elsif ($name =~ m/\A ((?:Sir|Dame) \s+ \S+)/xms) {
$salute = "Dear $1";
}
elsif ($name =~ m/([^\n]*), \s+ Ph[.]?D \z/xms) {
$sa1ute = "Dear Dr $1";
}
else {
$salute = "Dear $name";
}
with:
# Name format... # Salutat
+ion...
my $salute = $name eq $EMPTY_STR ? 'Dear Cus
+tomer'
: $name =~ m/ \A((?:Sir|Dame) \s+ \S+) /xms ? "Dear $1"
: $name =~ m/ (.*), \s+ Ph[.]?D \z /xms ? "Dear Dr
+$1"
: "Dear $na
+me"
;
and endorses the latter because:
- it avoids the (error-prone) repeated assignment to $salute
- it is more compact
- it looks like a table (if laid out as above)
- The syntax is stricter; for example, with the tabular ternary you can't accidentally leave off the final else clause, a mistake that might be made in the original version
| [reply] [d/l] [select] |
Re: Would you use a switch instead?
by Arunbear (Prior) on Jul 04, 2009 at 21:02 UTC
|
Whether to keep it or change it depends on what you find more readable. I find the switch feature more readable than nested ternaries:
use strict;
use warnings;
use feature qw( switch say );
sub test_it {
my $value = shift;
given($value) {
when(/aaa/) { return 'wanna' }
when(/bbb/) { return 'be' }
when(/ccc/) { return 'startin' }
default { return 'somethin' }
}
}
foreach my $str (qw[testaaa testbbb testccc testddd]) {
say test_it($str);
}
Update
I tried to remove the returns by wrapping the given in a do, but it seems the default/when blocks don't return anything to the do
in the way that if/else blocks do:
| [reply] [d/l] [select] |
|
Thanks for encapsulating the code in question into a subroutine. I always felt that this makes for easier-to-read high-level code, and permits modifying how the underlying test is done with minimal high-level changes.
| [reply] |
Re: Would you use a switch instead?
by JavaFan (Canon) on Jul 04, 2009 at 13:26 UTC
|
I'd leave it as is. Even if I would not have written it that way (I'd leave off the parens, and if I wanted to localize $_, I'd use a do {} block), I don't see the benefit of putting resources in changing it. | [reply] |
|
Can you please show me how you would use a do{} block instead of local?
| [reply] |
|
my $foo = do {
local $_ = $value;
/aaa/ ? 'wanna' :
/bbb/ ? 'be' :
/ccc/ ? 'startin' : 'somethin'
};
| [reply] [d/l] |
|
Re: Would you use a switch instead?
by Marshall (Canon) on Jul 06, 2009 at 11:46 UTC
|
I personally wouldn't do it this way:
###
local $_ = $value;
my $foo = (/aaa/) ? 'wanna' :
(/bbb/) ? 'be' :
(/ccc/) ? 'startin' : 'somethin';
###
Point 1: "local" is a "rare duck" - it happens seldom.
Almost always "my" is better. local is an artifact
of previous Perl versions, but it still has uses.
Point 2: I figure that setting $_ as an lvalue is a bad idea.
That is motivated the fact that Perl can and will
do this by itself.
Point 3: I have no problem with ternary expressions. But I
I do have a problem with an ":" without a "blah;"
Point 4: If we have a complex decision with 4 values, probably
we can come up with a name for that decision and
I'd name a sub{} with that name.
Point 5: If the thing we are searching is small and performance
is not an issue, I would omit "last" and "next"
in the interest of simplicity.
So, this is one way to do this..
my $foo = decide($value);
sub decide
{
my $value = shift;
my $decision = 'somethin';
foreach ($value) #sets $_ to $value!
{
$decision = 'wanna' if (/aaa/);
$decision = 'be' if (/bbb/);
$decision = 'startin' if (/ccc/);
}
return ($decision );
}
Perl is a fantastic tool. The above is just one way to approach this problem.
Update:In many languages, the return value of decide() would be true/false. Perl can return a string from a sub and this enhances the readability.
if $foo eq 'be'{...do xxxx...}
| [reply] [d/l] [select] |