in reply to Re^4: fall through switch/case in perl
in thread fall through switch/case in perl

Hmm. I think what your saying is that the eval is necessary to avoid a warning if $var doesn't contain a value for which there is a label defined?

If so, then it still doesn't handle the case where $var is undefined.

That can be handled by using a do BLOCK construct to disable warnings and adding a CASE0:

for my $var ( undef, 1 .. 10, 'fred' ) { goto 'CASE' . do{ local $^W; $var + 0 }; 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"; CASE0: }
I sort of wonder why this isn't given as one of the ways of achieving C-like switch statement behavior in the perl docs? Oh, well... it's probably horribly inefficient or something (apart from just being to C-ish or something).

C-ish it may be (though that's not a good reason in my book if it is clearer), but inefficient it is not:

P:\test>388915 ?> 1..10 Testing for vals [1..10] Rate if_cascade and_cascade goto_do goto_eval + goto if_cascade 11395/s -- -2% -11% -26% + -26% and_cascade 11627/s 2% -- -9% -24% + -25% goto_do 12845/s 13% 10% -- -17% + -17% goto_eval 15389/s 35% 32% 20% -- + -0% goto 15423/s 35% 33% 20% 0% + -- ?>

Benchmark/results

#! perl -sw use strict; use Benchmark qw[ cmpthese ]; our $DEBUG ||=0; our $ITERS = $DEBUG ? 1 : -3; $DEBUG or open STDOUT, '> :raw', \my( $mem ) or die $!; my $tests = { goto_eval => q[ $DEBUG and print "\ngoto_eval\n"; for my $var ( @inputs ) { eval { goto "CASE$var" } or goto DEFAULT; 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"; DEFAULT: } ], goto_do => q[ $DEBUG and print "\ngoto_do\n"; for my $var ( @inputs ) { goto 'CASE' . do{ local $^W; $var + 0 }; 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"; CASE0: } ], goto => q[ $DEBUG and print "\ngoto\n"; for my $var ( @inputs ) { goto 'CASE' . ($var + 0); 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"; CASE0: } ], if_cascade => q[ $DEBUG and print "\nif_cascade\n"; for my $var ( @inputs ) { 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 ); } print "\n"; } ], and_cascade => q[ $DEBUG and print "\nand_cascade\n"; for my $var ( @inputs ) { 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"; } print "\n"; } ], }; print STDERR '?> '; while( <STDIN> ) { chomp; warn "Testing for vals [$_]\n"; our @inputs = eval; cmpthese $ITERS, $tests; print STDERR '?> '; } __END__ P:\test>388915 ?> 1..10 Testing for vals [1..10] Rate if_cascade and_cascade goto_do goto_eval + goto if_cascade 11395/s -- -2% -11% -26% + -26% and_cascade 11627/s 2% -- -9% -24% + -25% goto_do 12845/s 13% 10% -- -17% + -17% goto_eval 15389/s 35% 32% 20% -- + -0% goto 15423/s 35% 33% 20% 0% + -- ?> P:\test>388915 -DEBUG=1 ?> 1..10, 'fred', undef Testing for vals [1..10, 'fred', undef] and_cascade j ij hij ghij fghij efghij defghij cdefghij bcdefghij abcdefghij Argument "fred" isn't numeric in numeric ge (>=) at (eval 5) line 5, < +STDIN> line 1. Use of uninitialized value in numeric ge (>=) at (eval 5) line 5, <STD +IN> line 1. Use of uninitialized value in numeric ge (>=) at (eval 5) line 6, <STD +IN> line 1. Use of uninitialized value in numeric ge (>=) at (eval 5) line 7, <STD +IN> line 1. Use of uninitialized value in numeric ge (>=) at (eval 5) line 8, <STD +IN> line 1. Use of uninitialized value in numeric ge (>=) at (eval 5) line 9, <STD +IN> line 1. Use of uninitialized value in numeric ge (>=) at (eval 5) line 10, <ST +DIN> line 1. Use of uninitialized value in numeric ge (>=) at (eval 5) line 11, <ST +DIN> line 1. Use of uninitialized value in numeric ge (>=) at (eval 5) line 12, <ST +DIN> line 1. Use of uninitialized value in numeric ge (>=) at (eval 5) line 13, <ST +DIN> line 1. Use of uninitialized value in numeric ge (>=) at (eval 5) line 14, <ST +DIN> line 1. (warning: too few iterations for a reliable count) goto j ij hij ghij fghij efghij defghij cdefghij bcdefghij abcdefghij Use of uninitialized value in addition (+) at (eval 7) line 4, <STDIN> + line 1. (warning: too few iterations for a reliable count) goto_do j ij hij ghij fghij efghij defghij cdefghij bcdefghij abcdefghij (warning: too few iterations for a reliable count) goto_eval j ij hij ghij fghij efghij defghij cdefghij bcdefghij abcdefghij Use of uninitialized value in concatenation (.) or string at (eval 11) + line 4, <STDIN> line 1. (warning: too few iterations for a reliable count) if_cascade j ij hij ghij fghij efghij defghij cdefghij bcdefghij abcdefghij Use of uninitialized value in numeric ge (>=) at (eval 13) line 5, <ST +DIN> line 1. Use of uninitialized value in numeric ge (>=) at (eval 13) line 6, <ST +DIN> line 1. Use of uninitialized value in numeric ge (>=) at (eval 13) line 7, <ST +DIN> line 1. Use of uninitialized value in numeric ge (>=) at (eval 13) line 8, <ST +DIN> line 1. Use of uninitialized value in numeric ge (>=) at (eval 13) line 9, <ST +DIN> line 1. Use of uninitialized value in numeric ge (>=) at (eval 13) line 10, <S +TDIN> line 1. Use of uninitialized value in numeric ge (>=) at (eval 13) line 11, <S +TDIN> line 1. Use of uninitialized value in numeric ge (>=) at (eval 13) line 12, <S +TDIN> line 1. Use of uninitialized value in numeric ge (>=) at (eval 13) line 13, <S +TDIN> line 1. Use of uninitialized value in numeric ge (>=) at (eval 13) line 14, <S +TDIN> line 1. (warning: too few iterations for a reliable count) Rate goto_do and_cascade goto_eval goto +if_cascade goto_do 1000000000000000/s -- 0% 0% 0% + 0% and_cascade 1000000000000000/s 0% -- 0% 0% + 0% goto_eval 1000000000000000/s 0% 0% -- 0% + 0% goto 1000000000000000/s 0% 0% 0% -- + 0% if_cascade 1000000000000000/s 0% 0% 0% 0% + -- ?> ^Z

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

Replies are listed 'Best First'.
Re^6: fall through switch/case in perl
by etcshadow (Priest) on Sep 07, 2004 at 05:44 UTC
    Hmm. I think what your saying is that the eval is necessary to avoid a warning if $var doesn't contain a value for which there is a label defined?
    No, I'm saying that goto $label dies if the label has not been defined. That is not how it works in C. In C, if you have not provided a case that matches your switch value, it jumps to the default case. That's why there's an eval, to prevent the die (not warning).
    [sstone@granite sstone]$ perl -le 'print 1; goto "FOO"; print 2' 1 Can't find label FOO at -e line 1. [sstone@granite sstone]$
    As far as preventing a warning on undef, well... I'd imagine that that should fit into whatever scheme you are using around undefs: warn if you have undef warnings on, else not. And there's nothing about stringifying $var that changes that semantic, so all seems well and good with my method.
    ------------ :Wq Not an editor command: Wq

      Fair enough, but in TimToady's original, he had 'CASE'.($var+0) which avoids dieing.

      P:\test>perl -le" print 1; $var = 'foo'; goto 'CASE'.($var+0); CASE0: +print 2;" 1 2

      And that allows CASE0: to become the default.

      The only situation this doesn't cover is when $var is undef'd; but then none of the other solutions handle that (except the do{ local $^W; $var + 0 }; I suggested).


      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
        Yes, but what if $var were 11? (Insert Spinal-Tap joke here).

        Also, as I said: when it comes to the behavior of undef (as the value of $var), shouldn't the surrounding scope's notion of whether or not to warn on undef apply here? Why should this be different (in that specific regard: i.e., whether or not to warn on using an undefined value) than, say, $var == 10 (etetera). I would think that if warnings were on, it SHOULD warn, and if warnings were not on, then it should NOT warn... and that's what you get. The presence of an eval doesn't change that fact.

        I'm confused... are we arguing or agreeing? :-D

        ------------ :Wq Not an editor command: Wq
      goto qw [CASE1 CASE2 CASE3 CASE4 CASE5 CASE6 CASE7 CASE8 CASE9 CASE10] [$var - 1] || "default"; 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"; default:
        You missed the $var=undef and $var<=0 cases.
        goto (undef, 'CASE01' .. 'CASE10')[abs($var) == $var ? $var+0 : 0]||"d +efault"; CASE10: print "a"; CASE09: print "b"; CASE08: print "c"; CASE07: print "d"; CASE06: print "e"; CASE05: print "f"; CASE04: print "g"; CASE03: print "h"; CASE02: print "i"; CASE01: print "j"; print "\n"; default:

        Search, Ask, Know