10 # LOAD FILTERING MODULE...
11 use Filter::Util::Call;
15 # CATCH ATTEMPTS TO CALL case OUTSIDE THE SCOPE OF ANY switch
17 $::_S_W_I_T_C_H = sub { croak "case/when statement not in switch/given block" };
21 my ($Perl5, $Perl6) = (0,0);
25 $fallthrough = grep /\bfallthrough\b/, @_;
26 $offset = (caller)[2]+1;
27 filter_add({}) unless @_>1 && $_[1] eq 'noimport';
30 for ( qw( on_defined on_exists ) )
32 *{"${pkg}::$_"} = \&$_;
34 *{"${pkg}::__"} = \&__ if grep /__/, @_;
35 $Perl6 = 1 if grep(/Perl\s*6/i, @_);
36 $Perl5 = 1 if grep(/Perl\s*5/i, @_) || !grep(/Perl\s*6/i, @_);
48 local $Switch::file = (caller)[1];
51 $status = filter_read(10_000);
52 return $status if $status<0;
53 $_ = filter_blocks($_,$offset);
54 $_ = "# line $offset\n" . $_ if $offset; undef $offset;
59 use Text::Balanced ':ALL';
63 my ($pretext,$offset) = @_;
64 ($pretext=~tr/\n/\n/)+($offset||0);
69 local $SIG{__WARN__}=sub{die$@};
71 my $ishash = defined eval 'my $hr='.$_[0];
77 my $EOP = qr/\n\n|\Z/;
78 my $CUT = qr/\n=cut.*$EOP/;
79 my $pod_or_DATA = qr/ ^=(?:head[1-4]|item) .*? $CUT
82 | ^=begin \s* (\S+) .*? \n=end \s* \1 .*? $EOP
89 my ($source, $line) = @_;
90 return $source unless $Perl5 && $source =~ /case|switch/
91 || $Perl6 && $source =~ /when|given/;
95 component: while (pos $source < length $source)
97 if ($source =~ m/(\G\s*use\s+Switch\b)/gc)
99 $text .= q{use Switch 'noimport'};
102 my @pos = Text::Balanced::_match_quotelike(\$source,qr/\s*/,1,0);
105 $text .= " " . substr($source,$pos[2],$pos[18]-$pos[2]);
108 if ($source =~ m/\G\s*($pod_or_DATA)/gc) {
111 @pos = Text::Balanced::_match_variable(\$source,qr/\s*/);
114 $text .= " " . substr($source,$pos[0],$pos[4]-$pos[0]);
118 if ($Perl5 && $source =~ m/\G(\n*)(\s*)(switch)\b(?=\s*[(])/gc
119 || $Perl6 && $source =~ m/\G(\n*)(\s*)(given)\b(?=\s*[(])/gc
120 || $Perl6 && $source =~ m/\G(\n*)(\s*)(given)\b(.*)(?=\{)/gc)
124 # print STDERR "[$arg]\n";
125 $text .= $1.$2.'S_W_I_T_C_H: while (1) ';
127 @pos = Text::Balanced::_match_codeblock(\$source,qr/\s*/,qr/\(/,qr/\)/,qr/[[{(<]/,qr/[]})>]/,undef)
129 die "Bad $keyword statement (problem in the parentheses?) near $Switch::file line ", line(substr($source,0,pos $source),$line), "\n";
131 $arg = filter_blocks(substr($source,$pos[0],$pos[4]-$pos[0]),line(substr($source,0,$pos[0]),$line));
133 $arg =~ s {^\s*[(]\s*%} { ( \\\%} ||
134 $arg =~ s {^\s*[(]\s*m\b} { ( qr} ||
135 $arg =~ s {^\s*[(]\s*/} { ( qr/} ||
136 $arg =~ s {^\s*[(]\s*qw} { ( \\qw};
137 @pos = Text::Balanced::_match_codeblock(\$source,qr/\s*/,qr/\{/,qr/\}/,qr/\{/,qr/\}/,undef)
139 die "Bad $keyword statement (problem in the code block?) near $Switch::file line ", line(substr($source,0, pos $source), $line), "\n";
141 my $code = filter_blocks(substr($source,$pos[0],$pos[4]-$pos[0]),line(substr($source,0,$pos[0]),$line));
142 $code =~ s/{/{ local \$::_S_W_I_T_C_H; Switch::switch $arg;/;
143 $text .= $code . 'continue {last}';
146 elsif ($Perl5 && $source =~ m/\G(\s*)(case\b)(?!\s*=>)/gc
147 || $Perl6 && $source =~ m/\G(\s*)(when\b)(?!\s*=>)/gc)
150 $text .= $1."if (Switch::case";
151 if (@pos = Text::Balanced::_match_codeblock(\$source,qr/\s*/,qr/\{/,qr/\}/,qr/\{/,qr/\}/,undef)) {
152 my $code = substr($source,$pos[0],$pos[4]-$pos[0]);
153 $text .= " sub" if is_block $code;
154 $text .= " " . filter_blocks($code,line(substr($source,0,$pos[0]),$line)) . ")";
156 elsif (@pos = Text::Balanced::_match_codeblock(\$source,qr/\s*/,qr/[[(]/,qr/[])]/,qr/[[({]/,qr/[])}]/,undef)) {
157 my $code = filter_blocks(substr($source,$pos[0],$pos[4]-$pos[0]),line(substr($source,0,$pos[0]),$line));
158 $code =~ s {^\s*[(]\s*%} { ( \\\%} ||
159 $code =~ s {^\s*[(]\s*m\b} { ( qr} ||
160 $code =~ s {^\s*[(]\s*/} { ( qr/} ||
161 $code =~ s {^\s*[(]\s*qw} { ( \\qw};
164 elsif ($Perl6 && do{@pos = Text::Balanced::_match_variable(\$source,qr/\s*/)}) {
165 my $code = filter_blocks(substr($source,$pos[0],$pos[4]-$pos[0]),line(substr($source,0,$pos[0]),$line));
166 $code =~ s {^\s*%} { \%} ||
167 $code =~ s {^\s*@} { \@};
170 elsif ( @pos = Text::Balanced::_match_quotelike(\$source,qr/\s*/,1,0)) {
171 my $code = substr($source,$pos[2],$pos[18]-$pos[2]);
172 $code = filter_blocks($code,line(substr($source,0,$pos[2]),$line));
173 $code =~ s {^\s*m} { qr} ||
174 $code =~ s {^\s*/} { qr/} ||
175 $code =~ s {^\s*qw} { \\qw};
178 elsif ($Perl5 && $source =~ m/\G\s*(([^\$\@{])[^\$\@{]*)(?=\s*{)/gc
179 || $Perl6 && $source =~ m/\G\s*([^;{]*)()/gc) {
180 my $code = filter_blocks($1,line(substr($source,0,pos $source),$line));
181 $text .= ' \\' if $2 eq '%';
185 die "Bad $keyword statement (invalid $keyword value?) near $Switch::file line ", line(substr($source,0,pos $source), $line), "\n";
188 die "Missing opening brace or semi-colon after 'when' value near $Switch::file line ", line(substr($source,0,pos $source), $line), "\n"
189 unless !$Perl6 || $source =~ m/\G(\s*)(?=;|\{)/gc;
191 do{@pos = Text::Balanced::_match_codeblock(\$source,qr/\s*/,qr/\{/,qr/\}/,qr/\{/,qr/\}/,undef)}
193 if ($source =~ m/\G\s*(?=([};]|\Z))/gc) {
197 die "Bad $keyword statement (problem in the code block?) near $Switch::file line ", line(substr($source,0,pos $source),$line), "\n";
199 my $code = filter_blocks(substr($source,$pos[0],$pos[4]-$pos[0]),line(substr($source,0,$pos[0]),$line));
200 $code =~ s/}(?=\s*\Z)/;last S_W_I_T_C_H }/
202 $text .= "{ while (1) $code continue { goto C_A_S_E_$casecounter } last S_W_I_T_C_H; C_A_S_E_$casecounter: }";
207 $source =~ m/\G(\s*(-[sm]\s+|\w+|#.*\n|\W))/gc;
219 for my $nextx ( @$x )
221 my $numx = ref($nextx) || defined $nextx && (~$nextx&$nextx) eq 0;
222 for my $j ( 0..$#$y )
224 my $nexty = $y->[$j];
225 push @numy, ref($nexty) || defined $nexty && (~$nexty&$nexty) eq 0
227 return 1 if $numx && $numy[$j] && $nextx==$nexty
237 my $ref = @_==1 && ref($_[0]) eq 'HASH' ? $_[0] : { @_ };
243 my $ref = @_==1 && ref($_[0]) eq 'HASH' ? $_[0] : { @_ };
244 [ grep { defined $ref->{$_} } keys %$ref ]
249 my ($s_val) = @_ ? $_[0] : $_;
250 my $s_ref = ref $s_val;
252 if ($s_ref eq 'CODE')
255 sub { my $c_val = $_[0];
256 return $s_val == $c_val if ref $c_val eq 'CODE';
257 return $s_val->(@$c_val) if ref $c_val eq 'ARRAY';
258 return $s_val->($c_val);
261 elsif ($s_ref eq "" && defined $s_val && (~$s_val&$s_val) eq 0) # NUMERIC SCALAR
264 sub { my $c_val = $_[0];
265 my $c_ref = ref $c_val;
266 return $s_val == $c_val if $c_ref eq ""
268 && (~$c_val&$c_val) eq 0;
269 return $s_val eq $c_val if $c_ref eq "";
270 return in([$s_val],$c_val) if $c_ref eq 'ARRAY';
271 return $c_val->($s_val) if $c_ref eq 'CODE';
272 return $c_val->call($s_val) if $c_ref eq 'Switch';
273 return scalar $s_val=~/$c_val/
274 if $c_ref eq 'Regexp';
275 return scalar $c_val->{$s_val}
280 elsif ($s_ref eq "") # STRING SCALAR
283 sub { my $c_val = $_[0];
284 my $c_ref = ref $c_val;
285 return $s_val eq $c_val if $c_ref eq "";
286 return in([$s_val],$c_val) if $c_ref eq 'ARRAY';
287 return $c_val->($s_val) if $c_ref eq 'CODE';
288 return $c_val->call($s_val) if $c_ref eq 'Switch';
289 return scalar $s_val=~/$c_val/
290 if $c_ref eq 'Regexp';
291 return scalar $c_val->{$s_val}
296 elsif ($s_ref eq 'ARRAY')
299 sub { my $c_val = $_[0];
300 my $c_ref = ref $c_val;
301 return in($s_val,[$c_val]) if $c_ref eq "";
302 return in($s_val,$c_val) if $c_ref eq 'ARRAY';
303 return $c_val->(@$s_val) if $c_ref eq 'CODE';
304 return $c_val->call(@$s_val)
305 if $c_ref eq 'Switch';
306 return scalar grep {$_=~/$c_val/} @$s_val
307 if $c_ref eq 'Regexp';
308 return scalar grep {$c_val->{$_}} @$s_val
313 elsif ($s_ref eq 'Regexp')
316 sub { my $c_val = $_[0];
317 my $c_ref = ref $c_val;
318 return $c_val=~/s_val/ if $c_ref eq "";
319 return scalar grep {$_=~/s_val/} @$c_val
320 if $c_ref eq 'ARRAY';
321 return $c_val->($s_val) if $c_ref eq 'CODE';
322 return $c_val->call($s_val) if $c_ref eq 'Switch';
323 return $s_val eq $c_val if $c_ref eq 'Regexp';
324 return grep {$_=~/$s_val/ && $c_val->{$_}} keys %$c_val
329 elsif ($s_ref eq 'HASH')
332 sub { my $c_val = $_[0];
333 my $c_ref = ref $c_val;
334 return $s_val->{$c_val} if $c_ref eq "";
335 return scalar grep {$s_val->{$_}} @$c_val
336 if $c_ref eq 'ARRAY';
337 return $c_val->($s_val) if $c_ref eq 'CODE';
338 return $c_val->call($s_val) if $c_ref eq 'Switch';
339 return grep {$_=~/$c_val/ && $s_val->{"$_"}} keys %$s_val
340 if $c_ref eq 'Regexp';
341 return $s_val==$c_val if $c_ref eq 'HASH';
345 elsif ($s_ref eq 'Switch')
348 sub { my $c_val = $_[0];
349 return $s_val == $c_val if ref $c_val eq 'Switch';
350 return $s_val->call(@$c_val)
351 if ref $c_val eq 'ARRAY';
352 return $s_val->call($c_val);
357 croak "Cannot switch on $s_ref";
362 sub case($) { local $SIG{__WARN__} = \&carp;
363 $::_S_W_I_T_C_H->(@_); }
367 my $placeholder = bless { arity=>1, impl=>sub{$_[1+$_[0]]} };
369 sub __() { $placeholder }
374 bless { arity=>0, impl=>sub{$_[$index]} };
384 my ($self,@args) = @_;
385 return $self->{impl}->(0,@args);
393 my ($left, $right, $reversed) = @_;
394 ($right,$left) = @_ if $reversed;
396 my $rop = ref $right eq 'Switch'
398 : bless { arity=>0, impl=>sub{$right} };
400 my $lop = ref $left eq 'Switch'
402 : bless { arity=>0, impl=>sub{$left} };
404 my $arity = $lop->{arity} + $rop->{arity};
408 impl => sub { my $start = shift;
409 return $op->($lop->{impl}->($start,@_),
410 $rop->{impl}->($start+$lop->{arity},@_));
423 my $lop = ref $left eq 'Switch'
425 : bless { arity=>0, impl=>sub{$left} };
427 my $arity = $lop->{arity};
431 impl => sub { $op->($lop->{impl}->(@_)) }
438 "+" => meta_bop {$_[0] + $_[1]},
439 "-" => meta_bop {$_[0] - $_[1]},
440 "*" => meta_bop {$_[0] * $_[1]},
441 "/" => meta_bop {$_[0] / $_[1]},
442 "%" => meta_bop {$_[0] % $_[1]},
443 "**" => meta_bop {$_[0] ** $_[1]},
444 "<<" => meta_bop {$_[0] << $_[1]},
445 ">>" => meta_bop {$_[0] >> $_[1]},
446 "x" => meta_bop {$_[0] x $_[1]},
447 "." => meta_bop {$_[0] . $_[1]},
448 "<" => meta_bop {$_[0] < $_[1]},
449 "<=" => meta_bop {$_[0] <= $_[1]},
450 ">" => meta_bop {$_[0] > $_[1]},
451 ">=" => meta_bop {$_[0] >= $_[1]},
452 "==" => meta_bop {$_[0] == $_[1]},
453 "!=" => meta_bop {$_[0] != $_[1]},
454 "<=>" => meta_bop {$_[0] <=> $_[1]},
455 "lt" => meta_bop {$_[0] lt $_[1]},
456 "le" => meta_bop {$_[0] le $_[1]},
457 "gt" => meta_bop {$_[0] gt $_[1]},
458 "ge" => meta_bop {$_[0] ge $_[1]},
459 "eq" => meta_bop {$_[0] eq $_[1]},
460 "ne" => meta_bop {$_[0] ne $_[1]},
461 "cmp" => meta_bop {$_[0] cmp $_[1]},
462 "\&" => meta_bop {$_[0] & $_[1]},
463 "^" => meta_bop {$_[0] ^ $_[1]},
464 "|" => meta_bop {$_[0] | $_[1]},
465 "atan2" => meta_bop {atan2 $_[0], $_[1]},
467 "neg" => meta_uop {-$_[0]},
468 "!" => meta_uop {!$_[0]},
469 "~" => meta_uop {~$_[0]},
470 "cos" => meta_uop {cos $_[0]},
471 "sin" => meta_uop {sin $_[0]},
472 "exp" => meta_uop {exp $_[0]},
473 "abs" => meta_uop {abs $_[0]},
474 "log" => meta_uop {log $_[0]},
475 "sqrt" => meta_uop {sqrt $_[0]},
476 "bool" => sub { croak "Can't use && or || in expression containing __" },
478 # "&()" => sub { $_[0]->{impl} },
480 # "||" => meta_bop {$_[0] || $_[1]},
481 # "&&" => meta_bop {$_[0] && $_[1]},
491 Switch - A switch statement for Perl
495 This document describes version 2.07 of Switch,
496 released May 15, 2002.
504 case 1 { print "number 1" }
505 case "a" { print "string a" }
506 case [1..10,42] { print "number in list" }
507 case (@array) { print "number in list" }
508 case /\w+/ { print "pattern" }
509 case qr/\w+/ { print "pattern" }
510 case (%hash) { print "entry in hash" }
511 case (\%hash) { print "entry in hash" }
512 case (\&sub) { print "arg to subroutine" }
513 else { print "previous case not true" }
518 [Skip ahead to L<"DESCRIPTION"> if you don't care about the whys
519 and wherefores of this control structure]
521 In seeking to devise a "Swiss Army" case mechanism suitable for Perl,
522 it is useful to generalize this notion of distributed conditional
523 testing as far as possible. Specifically, the concept of "matching"
524 between the switch value and the various case values need not be
525 restricted to numeric (or string or referential) equality, as it is in other
526 languages. Indeed, as Table 1 illustrates, Perl
527 offers at least eighteen different ways in which two values could
530 Table 1: Matching a switch value ($s) with a case value ($c)
532 Switch Case Type of Match Implied Matching Code
534 ====== ===== ===================== =============
536 number same numeric or referential match if $s == $c;
539 object method result of method call match if $s->$c();
540 ref name match if defined $s->$c();
543 other other string equality match if $s eq $c;
547 string regexp pattern match match if $s =~ /$c/;
549 array scalar array entry existence match if 0<=$c && $c<@$s;
550 ref array entry definition match if defined $s->[$c];
551 array entry truth match if $s->[$c];
553 array array array intersection match if intersects(@$s, @$c);
554 ref ref (apply this table to
555 all pairs of elements
559 array regexp array grep match if grep /$c/, @$s;
562 hash scalar hash entry existence match if exists $s->{$c};
563 ref hash entry definition match if defined $s->{$c};
564 hash entry truth match if $s->{$c};
566 hash regexp hash grep match if grep /$c/, keys %$s;
569 sub scalar return value defn match if defined $s->($c);
570 ref return value truth match if $s->($c);
572 sub array return value defn match if defined $s->(@$c);
573 ref ref return value truth match if $s->(@$c);
576 In reality, Table 1 covers 31 alternatives, because only the equality and
577 intersection tests are commutative; in all other cases, the roles of
578 the C<$s> and C<$c> variables could be reversed to produce a
579 different test. For example, instead of testing a single hash for
580 the existence of a series of keys (C<match if exists $s-E<gt>{$c}>),
581 one could test for the existence of a single key in a series of hashes
582 (C<match if exists $c-E<gt>{$s}>).
584 As L<perltodo> observes, a Perl case mechanism must support all these
590 The Switch.pm module implements a generalized case mechanism that covers
591 the numerous possible combinations of switch and case values described above.
593 The module augments the standard Perl syntax with two new control
594 statements: C<switch> and C<case>. The C<switch> statement takes a
595 single scalar argument of any type, specified in parentheses.
596 C<switch> stores this value as the
597 current switch value in a (localized) control variable.
598 The value is followed by a block which may contain one or more
599 Perl statements (including the C<case> statement described below).
600 The block is unconditionally executed once the switch value has
603 A C<case> statement takes a single scalar argument (in mandatory
604 parentheses if it's a variable; otherwise the parens are optional) and
605 selects the appropriate type of matching between that argument and the
606 current switch value. The type of matching used is determined by the
607 respective types of the switch value and the C<case> argument, as
608 specified in Table 1. If the match is successful, the mandatory
609 block associated with the C<case> statement is executed.
611 In most other respects, the C<case> statement is semantically identical
612 to an C<if> statement. For example, it can be followed by an C<else>
613 clause, and can be used as a postfix statement qualifier.
615 However, when a C<case> block has been executed control is automatically
616 transferred to the statement after the immediately enclosing C<switch>
617 block, rather than to the next statement within the block. In other
618 words, the success of any C<case> statement prevents other cases in the
619 same scope from executing. But see L<"Allowing fall-through"> below.
621 Together these two new statements provide a fully generalized case
628 %special = ( woohoo => 1, d'oh => 1 );
633 case (%special) { print "homer\n"; } # if $special{$_}
634 case /a-z/i { print "alpha\n"; } # if $_ =~ /a-z/i
635 case [1..9] { print "small num\n"; } # if $_ in [1..9]
637 case { $_[0] >= 10 } { # if $_ >= 10
639 switch (sub{ $_[0] < $age } ) {
641 case 20 { print "teens\n"; } # if 20 < $age
642 case 30 { print "twenties\n"; } # if 30 < $age
643 else { print "history\n"; }
647 print "must be punctuation\n" case /\W/; # if $_ ~= /\W/
650 Note that C<switch>es can be nested within C<case> (or any other) blocks,
651 and a series of C<case> statements can try different types of matches
652 -- hash membership, pattern match, array intersection, simple equality,
653 etc. -- against the same switch value.
655 The use of intersection tests against an array reference is particularly
656 useful for aggregating integral cases:
660 switch ($_[0]) { case 0 { return 'zero' }
661 case [2,4,6,8] { return 'even' }
662 case [1,3,4,7,9] { return 'odd' }
663 case /[A-F]/i { return 'hex' }
668 =head2 Allowing fall-through
670 Fall-though (trying another case after one has already succeeded)
671 is usually a Bad Idea in a switch statement. However, this
672 is Perl, not a police state, so there I<is> a way to do it, if you must.
674 If a C<case> block executes an untargetted C<next>, control is
675 immediately transferred to the statement I<after> the C<case> statement
676 (i.e. usually another case), rather than out of the surrounding
682 case 1 { handle_num_1(); next } # and try next case...
683 case "1" { handle_str_1(); next } # and try next case...
684 case [0..9] { handle_num_any(); } # and we're done
685 case /\d/ { handle_dig_any(); next } # and try next case...
686 case /.*/ { handle_str_any(); next } # and try next case...
689 If $val held the number C<1>, the above C<switch> block would call the
690 first three C<handle_...> subroutines, jumping to the next case test
691 each time it encountered a C<next>. After the thrid C<case> block
692 was executed, control would jump to the end of the enclosing
695 On the other hand, if $val held C<10>, then only the last two C<handle_...>
696 subroutines would be called.
698 Note that this mechanism allows the notion of I<conditional fall-through>.
702 case [0..9] { handle_num_any(); next if $val < 7; }
703 case /\d/ { handle_dig_any(); }
706 If an untargetted C<last> statement is executed in a case block, this
707 immediately transfers control out of the enclosing C<switch> block
708 (in other words, there is an implicit C<last> at the end of each
709 normal C<case> block). Thus the previous example could also have been
713 case [0..9] { handle_num_any(); last if $val >= 7; next; }
714 case /\d/ { handle_dig_any(); }
718 =head2 Automating fall-through
720 In situations where case fall-through should be the norm, rather than an
721 exception, an endless succession of terminal C<next>s is tedious and ugly.
722 Hence, it is possible to reverse the default behaviour by specifying
723 the string "fallthrough" when importing the module. For example, the
724 following code is equivalent to the first example in L<"Allowing fall-through">:
726 use Switch 'fallthrough';
729 case 1 { handle_num_1(); }
730 case "1" { handle_str_1(); }
731 case [0..9] { handle_num_any(); last }
732 case /\d/ { handle_dig_any(); }
733 case /.*/ { handle_str_any(); }
736 Note the explicit use of a C<last> to preserve the non-fall-through
737 behaviour of the third case.
741 =head2 Alternative syntax
743 Perl 6 will provide a built-in switch statement with essentially the
744 same semantics as those offered by Switch.pm, but with a different
745 pair of keywords. In Perl 6 C<switch> will be spelled C<given>, and
746 C<case> will be pronounced C<when>. In addition, the C<when> statement
747 will not require switch or case values to be parenthesized.
749 This future syntax is also (largely) available via the Switch.pm module, by
750 importing it with the argument C<"Perl6">. For example:
755 when 1 { handle_num_1(); }
756 when ($str1) { handle_str_1(); }
757 when [0..9] { handle_num_any(); last }
758 when /\d/ { handle_dig_any(); }
759 when /.*/ { handle_str_any(); }
762 Note that scalars still need to be parenthesized, since they would be
765 Note too that you can mix and match both syntaxes by importing the module
768 use Switch 'Perl5', 'Perl6';
771 =head2 Higher-order Operations
773 One situation in which C<switch> and C<case> do not provide a good
774 substitute for a cascaded C<if>, is where a switch value needs to
775 be tested against a series of conditions. For example:
780 case sub { $_[0] < 10 } { return 'milk' }
781 case sub { $_[0] < 20 } { return 'coke' }
782 case sub { $_[0] < 30 } { return 'beer' }
783 case sub { $_[0] < 40 } { return 'wine' }
784 case sub { $_[0] < 50 } { return 'malt' }
785 case sub { $_[0] < 60 } { return 'Moet' }
786 else { return 'milk' }
790 The need to specify each condition as a subroutine block is tiresome. To
791 overcome this, when importing Switch.pm, a special "placeholder"
792 subroutine named C<__> [sic] may also be imported. This subroutine
793 converts (almost) any expression in which it appears to a reference to a
794 higher-order function. That is, the expression:
802 sub { $_[0] < 2 + $_[1] }
804 With C<__>, the previous ugly case statements can be rewritten:
806 case __ < 10 { return 'milk' }
807 case __ < 20 { return 'coke' }
808 case __ < 30 { return 'beer' }
809 case __ < 40 { return 'wine' }
810 case __ < 50 { return 'malt' }
811 case __ < 60 { return 'Moet' }
812 else { return 'milk' }
814 The C<__> subroutine makes extensive use of operator overloading to
815 perform its magic. All operations involving __ are overloaded to
816 produce an anonymous subroutine that implements a lazy version
817 of the original operation.
819 The only problem is that operator overloading does not allow the
820 boolean operators C<&&> and C<||> to be overloaded. So a case statement
823 case 0 <= __ && __ < 10 { return 'digit' }
825 doesn't act as expected, because when it is
826 executed, it constructs two higher order subroutines
827 and then treats the two resulting references as arguments to C<&&>:
829 sub { 0 <= $_[0] } && sub { $_[0] < 10 }
831 This boolean expression is inevitably true, since both references are
832 non-false. Fortunately, the overloaded C<'bool'> operator catches this
833 situation and flags it as a error.
837 The module is implemented using Filter::Util::Call and Text::Balanced
838 and requires both these modules to be installed.
842 Damian Conway (damian@conway.org)
846 There are undoubtedly serious bugs lurking somewhere in code this funky :-)
847 Bug reports and other feedback are most welcome.
851 Due to the heuristic nature of Switch.pm's source parsing, the presence
852 of regexes specified with raw C<?...?> delimiters may cause mysterious
853 errors. The workaround is to use C<m?...?> instead.
857 Copyright (c) 1997-2001, Damian Conway. All Rights Reserved.
858 This module is free software. It may be used, redistributed
859 and/or modified under the same terms as Perl itself.