Occasionally, people lament that Perl has no switch/case statement like C. Perl6 has given/when, which goes several steps beyond the simple switch by handling arbitrary conditions, rather than simple equivalence.

So what does it buy you over if-else? Not a lot, in my experience. You can save some keystrokes by not retyping what you're matching against, and sometimes the ability to control whether things "fall through" -- matching multiple cases -- can come in handy.

Of course, we are not entirely without alternatives in Perl5. For simple multi-candidate equality testing without defaulting or fall-through, you can use a hash:

my $consider = 'foo'; ${{ bar => sub { print "Barred!\n" }, foo => sub { print "Fooed for thought...\n" } }}{$consider}();
Grep is a natural tool for multi-way matching, and you can set it up to do fall-through and defaulting, though you do have to work at it:
{ my $continue = 1; $_->[1]() for grep { my ($cond, $then, $break)=@$_; local $_='boz'; # This is your given $continue and $cond->() and do { $continue = !defined $break; 1} } [sub {/z/}, sub { print "Hi!\n" }], [sub {/o/}, sub { print "Oh!\n" }, 'break'], [sub {1}, sub { print "This is the default\n" }] ; }
Clearly you could encapsulate this in a function that takes your given and the list of condition-then(-break) sub pairs/triplets.

Still not pretty enough? Then maybe I can interest you in something that looks a lot like Perl6's given (even though I think it should have been called "consider" for better reading):

{ my $continue = 1; sub given ($$) { local $_ = shift; my $next = shift; my ($cond, $then); while ($next) { ($cond, $then, $next) = @$next; $then->() if $cond->() and $then; $continue or last; } } sub when (&$) { [$_[0], @{$_[1]}] } sub then (&;$) { [@_] } sub default(&) { [@_] } sub done() { $continue = 0 } sub isit ($$) { my @args=@_; [sub { $_ eq $args[0] }, @{$args[1]}] +} } given 'baz', isit 'baz', then { print "String match!\n" } when {/z/} then { print "Hi!\n" } when {/o/} then { print "Oh!\n"; done } default { print "This is the default\n" } ;
Given can only consider a scalar, but otherwise it's pretty comparable to the Perl6 critter, eh?

Update: added isit sub, to provide implicit eq check against $_. Writing when {$_ eq 'something'} for a lot of cases would get pretty old.


Caution: Contents may have been coded under pressure.

In reply to Switch/case (given/when) in Perl5 by Roy Johnson

Title:
Use:  <p> text here (a paragraph) </p>
and:  <code> code here </code>
to format your post, it's "PerlMonks-approved HTML":



  • Posts are HTML formatted. Put <p> </p> tags around your paragraphs. Put <code> </code> tags around your code and data!
  • Titles consisting of a single word are discouraged, and in most cases are disallowed outright.
  • Read Where should I post X? if you're not absolutely sure you're posting in the right place.
  • Please read these before you post! —
  • Posts may use any of the Perl Monks Approved HTML tags:
    a, abbr, b, big, blockquote, br, caption, center, col, colgroup, dd, del, details, div, dl, dt, em, font, h1, h2, h3, h4, h5, h6, hr, i, ins, li, ol, p, pre, readmore, small, span, spoiler, strike, strong, sub, summary, sup, table, tbody, td, tfoot, th, thead, tr, tt, u, ul, wbr
  • You may need to use entities for some characters, as follows. (Exception: Within code tags, you can put the characters literally.)
            For:     Use:
    & &amp;
    < &lt;
    > &gt;
    [ &#91;
    ] &#93;
  • Link using PerlMonks shortcuts! What shortcuts can I use for linking?
  • See Writeup Formatting Tips and other pages linked from there for more info.