Re: fall through switch/case in perl
by Velaki (Chaplain) on Sep 06, 2004 at 23:50 UTC
|
If you really want the case statement, there are
many ways of doing it, as per the Programming Perl, a.k.a. the "Camel" book.
However, I think the following might be more what you need.
print substr("abcdefghij",10-$var),"\n";
Hope that helped,
-v
"Perl. There is no substitute."
| [reply] [Watch: Dir/Any] [d/l] |
|
| [reply] [Watch: Dir/Any] [d/l] [select] |
Re: fall through switch/case in perl
by etcshadow (Priest) on Sep 07, 2004 at 00:27 UTC
|
Well, what the first couple folks said doesn't actually answer your question... they were answering what *would* have been your question if you *had* had break statements... I don't know if the original post was updated after the fact or if they simply did not actually read it... whatever.
The short answer is that there isn't anything that does this very well, and in the same way as C does. The thing to understand is that switch statements in C are actually just well-written GOTO statements! Likewise, the best way to do this might be GOTOs (as bad as that might sound)... or just coding it explicitly, something like:
for ( $var ) {
my $go;
($go || $_ == 10) and $go++, print "a";
($go || $_ == 9 ) and $go++, print "b";
($go || $_ == 8 ) and $go++, print "c";
($go || $_ == 7 ) and $go++, print "d";
($go || $_ == 6 ) and $go++, print "e";
($go || $_ == 5 ) and $go++, print "f";
($go || $_ == 4 ) and $go++, print "g";
($go || $_ == 3 ) and $go++, print "h";
($go || $_ == 2 ) and $go++, print "i";
($go || $_ == 1 ) and $go++, print "j";
}
------------
:Wq
Not an editor command: Wq
| [reply] [Watch: Dir/Any] [d/l] [select] |
|
Here's the computed goto version:
eval { goto 'L'.($var+0) }; die "$var out of range";
L10: print "a";
L9: print "b";
L8: print "c";
L7: print "d";
L6: print "e";
L5: print "f";
L4: print "g";
L3: print "h";
L2: print "i";
L1: print "j";
print "\n";
| [reply] [Watch: Dir/Any] [d/l] |
|
eval { goto 'L'.($var+0) }; goto L_default;
L10: print "a";
L9: print "b";
L8: print "c";
L7: print "d";
L6: print "e";
L5: print "f";
L4: print "g";
L3: print "h";
L2: print "i";
L1: print "j";
L_default:
print "\n";
to preserve the semantics of the original code?
Makeshifts last the longest.
| [reply] [Watch: Dir/Any] [d/l] |
|
#! perl -sw
use strict;
my $var = 7;
goto 'CASE'.($var+0); die "$var out of range";
CASE10: print "a";
CASE9: print "b";
CASE8: print "c";
CASE7: print "d";
CASE6: print "e";
CASE5: print "f";
CASE4: print "g";
CASE3: print "h";
CASE2: print "i";
CASE1: print "j";
print "\n";
__END__
P:\test>junk
defghij
Examine what is said, not who speaks.
"Efficiency is intelligent laziness." -David Dunham
"Think for yourself!" - Abigail
"Memory, processor, disk in that order on the hardware side. Algorithm, algorithm, algorithm on the code side." - tachyon
| [reply] [Watch: Dir/Any] [d/l] |
|
|
|
Re: fall through switch/case in perl
by Aristotle (Chancellor) on Sep 07, 2004 at 01:03 UTC
|
Warning: may cause nausea. Posted purely for hack value. An indent of 2 spaces used to protect the right margin from harm. Don't try this at home.
for ( $var ) {
$_ == 1 or do {
$_ == 2 or do {
$_ == 3 or do {
$_ == 4 or do {
$_ == 5 or do {
$_ == 6 or do {
$_ == 7 or do {
$_ == 8 or do {
$_ == 9 or do {
$_ == 10 or do {
last;
};
print "a";
};
print "b";
};
print "c";
};
print "d";
};
print "e";
};
print "f";
};
print "g";
};
print "h";
};
print "i";
};
print "j";
}
Makeshifts last the longest.
| [reply] [Watch: Dir/Any] [d/l] |
Re: fall through switch/case in perl
by TomDLux (Vicar) on Sep 07, 2004 at 01:41 UTC
|
The inherent weakness in your query is that you are asking
for a Perl equivalent to a basic 'switch' idiom, when Perl
doesn't provide a 'switch' construct.
You are asking about Duff's Device ..... which,
as I remember, was invented to save a couple dozen machine instructions.
My understanding is that Duff's Device is mostly viewed as poor programming,
since saving a few dozen machine cycles at 3 GHz is less important than
leading to quick and clear reader understanding of the code. On the other
hand, I can imagine programmers dealing with highly-efficient code, such as embedded programmers, might accept Duff as an easily recognized idiom.
So the next question is, without a switch statement, how would we implement Duff?
We've had one suggestion, using substr(), very closely related to the details of this question.
More generally, you might consider re-framing the conditionals:
for my $val ( $var ) {
print "a" if ( $val >= 10 );
print "b" if ( $val >= 9 );
print "c" if ( $val >= 8 );
print "d" if ( $val >= 7 );
print "e" if ( $val >= 6 );
print "f" if ( $val >= 5 );
print "g" if ( $val >= 4 );
print "h" if ( $val >= 3 );
print "i" if ( $val >= 2 );
print "j" if ( $val >= 1 );
}
So, yes, it can be achieved, but you need to think somewhat differently.
--
TTTATCGGTCGTTATATAGATGTTTGCA
| [reply] [Watch: Dir/Any] [d/l] |
|
Actually, this is just a standard switch statement,-- not Duff's device.
On the clarity argument, it's very much in the eye of the beholder whether your if cascade (or the and cascade) is clearer than the computed-goto version?
For completeness, the computed goto version works out an average of over 60% faster than either of the cascade versions, which is rather more than a few dozen clock cycles.
Examine what is said, not who speaks.
"Efficiency is intelligent laziness." -David Dunham
"Think for yourself!" - Abigail
"Memory, processor, disk in that order on the hardware side. Algorithm, algorithm, algorithm on the code side." - tachyon
| [reply] [Watch: Dir/Any] |
|
| [reply] [Watch: Dir/Any] |
|
|
- The OP isn't asking about Duff's device.
- Your code isn't Duff's device either.
- Your code is inefficient (it's always doing 10 comparisons).
- Your code has a pointless for loop.
| [reply] [Watch: Dir/Any] |
Re: fall through switch/case in perl (w/closure)
by demerphq (Chancellor) on Sep 07, 2004 at 07:08 UTC
|
#!perl -l
my $var=9;
my @sub=(0,map { sub { print $_ } } reverse 'a'..'j');
if ($var>=0 and $var<=$#sub) {
$sub[$_] && $sub[$_]->() for reverse 1..$var;
}
---
demerphq
First they ignore you, then they laugh at you, then they fight you, then you win.
-- Gandhi
| [reply] [Watch: Dir/Any] [d/l] |
Re: fall through switch/case in perl
by DamnDirtyApe (Curate) on Sep 07, 2004 at 07:12 UTC
|
The first answer that came to mind was the Switch module, but for some reason it doesn't seem to be behaving as expected. Can anyone tell me why this doesn't do what it looks like it should do?
#! /usr/bin/perl
use strict;
use Switch 'fallthrough';
sub test_switch {
my $val = shift;
switch ( $val ) {
case 10 { print "a"; }
case 9 { print "b"; }
case 8 { print "c"; }
case 7 { print "d"; }
case 6 { print "e"; }
case 5 { print "f"; }
case 4 { print "g"; }
case 3 { print "h"; }
case 2 { print "i"; }
case 1 { print "j"; }
}
}
test_switch( 10 );
print "\n";
test_switch( 5 );
print "\n";
__END__
Results:
a
f
Maybe I'm overlooking something, but I'm failing to see why this isn't doing just what the OP asked for. Please help.
_______________
DamnDirtyApe
Those who know that they are profound strive for clarity. Those who
would like to seem profound to the crowd strive for obscurity.
--Friedrich Nietzsche
| [reply] [Watch: Dir/Any] [d/l] [select] |
|
I looked at Switch first, too. The thing with Switch 'fallthrough' is that it falls to the next condition, not the next bit of code (like it does in C).
If each successive condition is inclusive of all its predessors, you can do it with Switch 'fallthrough':
use Switch 'fallthrough';
sub test_switch {
my $val = shift;
switch ( $val ) {
case 10 { print "a"; }
case [9..10] { print "b"; }
case [8..10] { print "c"; }
case [7..10] { print "d"; }
case [6..10] { print "e"; }
case [5..10] { print "f"; }
case [4..10] { print "g"; }
case [3..10] { print "h"; }
case [2..10] { print "i"; }
case [1..10] { print "j"; }
}
}
This is hard to extend beyond the realm of successive integers, of course.
| [reply] [Watch: Dir/Any] [d/l] |
Re: fall through switch/case in perl
by Zed_Lopez (Chaplain) on Sep 07, 2004 at 05:36 UTC
|
my %switch;
@switch{1..10} = (qw(L1 L2 L3 L4 L5 L6 L7 L8 L9 L10));
goto END_SWITCH unless exists $switch{$var};
goto $switch{$var};
L10: print "a" ;
L9: print "b" ;
L8: print "c" ;
L7: print "d" ;
L6: print "e" ;
L5: print "f" ;
L4: print "g" ;
L3: print "h" ;
L2: print "i" ;
L1: print "j" ;
END_SWITCH: # whatever
| [reply] [Watch: Dir/Any] [d/l] |
Re: fall through switch/case in perl
by Anonymous Monk on Sep 07, 2004 at 08:42 UTC
|
Thank you guys very much !
I've found here many ways to do this switch.
Especially for etcshadow for his original way.
Thanks TimToady, Aristotle, BrowserUk for example with eval-ed goto (actually I was thinking abiut this way when i was wakin up today).
Aristotle nested do works, but code looks very ugly ;)
TomDLux does not solve fallthrugh case in general, but perfectly suits for my case (i choosed such solution, thank you).
Very original solution gave me demerphq, but it not sutable for me because i'm doing some computation work (instead of prints, which I've chosed for example of how fall through works for people not familar with C).
substr actually does not fit, because i've choosed print as example of fall through (as i said earlier).
PS. I'm new to perlmonks, but my first impression is great !
PPS. Does anybody knows where I can post tips at perlmonks (i've found a nice way to make addition and subtraction by modulo 2^32 on machines where perl compiled with use64bitint=undef)
| [reply] [Watch: Dir/Any] |
|
| [reply] [Watch: Dir/Any] |
Re: fall through switch/case in perl
by Aristotle (Chancellor) on Sep 06, 2004 at 23:45 UTC
|
for ( $var ) {
$_ == 10 and print "a";
$_ == 9 and print "b";
$_ == 8 and print "c";
$_ == 7 and print "d";
$_ == 6 and print "e";
$_ == 5 and print "f";
$_ == 4 and print "g";
$_ == 3 and print "h";
$_ == 2 and print "i";
$_ == 1 and print "j";
}
There are about ten million other ways to say the same, of course.
Makeshifts last the longest.
| [reply] [Watch: Dir/Any] [d/l] |
|
You missed his note about "fall through" ala C.
In his example, a value of '5' would produce "fghij". A value of '2' would produce "ij". Velaki's code recognizes this better.
But I wonder if he might ever have var set to zero? (No output!)
| [reply] [Watch: Dir/Any] |
|
| [reply] [Watch: Dir/Any] |
|
|
|
|
Mhm wonder what happens if $var is 20000000000 or -1.
| [reply] [Watch: Dir/Any] |
|
| [reply] [Watch: Dir/Any] |
Re: fall through switch/case in perl
by jeffa (Bishop) on Sep 07, 2004 at 18:50 UTC
|
I don't think i have seen this one yet, although it is close in spirit to demerphq's solution:
use strict;
no warnings;
my @array = reverse 'a' .. 'j';
my $var = shift() - 1;
print join '', reverse @array[0..$var];
Update: one-liner for the heck of it
perl -le"@_=reverse a..j;print join'',reverse@_[0..shift()-1]" 5
| [reply] [Watch: Dir/Any] [d/l] [select] |
|
perl -le "print((a..j)[-shift..-1])" 5
| [reply] [Watch: Dir/Any] [d/l] |
Re: fall through switch/case in perl
by radiantmatrix (Parson) on Sep 07, 2004 at 15:08 UTC
|
Your example problem is fairly simple, but for more complicated switch-like behavior,
my @switch_foo = ("a","b","c",...);
for ($var) {
my $junk = shift;
while ($junk > 0) {
print $switch_foo[$junk]);
$junk--;
}
}
It's way overkill for your particular problem, but for commplicated situations, @switch_foo can contain references to subs, making it quite powerful (if a little slow).
In practice, however, if your algorithm needs a switch equivalent, you're better off re-thinking your algorithm.
Update: fixed the code so that it works!
--
$me = rand($hacker{perl});
| [reply] [Watch: Dir/Any] [d/l] |
|
Your code will either not print anything, or it'll never finish printing.
In practice, however, if your algorithm needs a switch equivalent, you're better off re-thinking your algorithm.
Eh? And why is that? That's a pretty bold statement, considering many languages do have a 'switch', perl6 will have a switch, there's Switch.pm, both the manual and the FAQ discuss it (without dismissing it as choicing a bad algorithm), and it has been on the wishlist since the very first release of Perl in 1987.
| [reply] [Watch: Dir/Any] |
|
Your code will either not print anything, or it'll never finish printing.
You're right, I forgot the $junk--; after the print statement.
That's a pretty bold statement, considering many languages do have a 'switch', perl6 will have a switch, there's Switch.pm, both the manual and the FAQ discuss it (without dismissing it as choicing a bad algorithm), and it has been on the wishlist since the very first release of Perl in 1987.
I never said switch was bad code. Perl6 will have a switch because a lot of people want it, and it is very readable. However, switch statements are unbelievably over-used. I stand by my statement; chances are, if your algorithm needs switch, you can come up with a better algorithm. There are, of course, a few exceptions.
As to your "considering many languages have a 'switch'", multiplicity does not correctness make.
--
$me = rand($hacker{perl});
| [reply] [Watch: Dir/Any] |
|
|
|