lurks
lurks

Reputation: 2606

Obtain a switch/case behaviour in Perl 5

Is there a neat way of making a case or switch statement in Perl 5?. It seems to me they should include a switch on version 6.

I need this control structure in a script, and I've heard you can import a "switch module". But how can I achieve it without imports to minimize dependencies and acquire portability?

Upvotes: 29

Views: 42382

Answers (6)

Rawley Fowler
Rawley Fowler

Reputation: 2564

When Perl v5.42 is released, the existing given, when is going away.

You can use Switch::Right if you want to use the given, when syntax but with a more sane smart-matching, and with "good enough" backwards compatibility with the departing feature:

use Switch::Right;
 
given ($value) {
    when (undef)    { say 'an undefined value' }
    when (1)        { say 'the number 1' }
    when ('two')    { say 'the string "two"' }
    when (defined && length > 0) { say 'a non-empty string' }
};

Upvotes: 1

Weeble
Weeble

Reputation: 11

print("OK : 1 - CANCEL : 2\n");
my $value = <STDIN>;
SWITCH: {
    ($value == 1) && last(SWITCH);
    ($value == 2) && do {print("Cancelled\n"); exit()};
    print("??\n");
}

Upvotes: 1

tsee
tsee

Reputation: 5072

Just a short comment about the core Switch module that's been mentioned a couple of times in answers. The module in question relies on source filters. Among other things, that may result in wrong lines reported for errors. It's so bad that none of the core developers really remembers or cares to remember why it was accepted into the perl core in the first place.

Furthermore, Switch.pm will be the first Perl module ever to be removed from the perl core. The next major release of perl, 5.12.0, will still have it, albeit with a deprecation warning. That deprecation warning will go away if you explicitly install Switch.pm from CPAN. (You get what you ask for.) In the next release down the road, 5.14, Switch.pm will be entirely removed from core.

Upvotes: 12

jiggy
jiggy

Reputation: 3826

An equivalent solution that I like is a dispatch table.

my $switch = {
  'case1' => sub { print "case1"; },
  'case2' => sub { print "case2"; },
  'default' => sub { print "unrecognized"; }
};
$switch->{$case} ? $switch->{$case}->() : $switch->{'default'}->();

Upvotes: 10

Chas. Owens
Chas. Owens

Reputation: 64919

If you are using Perl 5.10 you have given/when which is a switch statement (note, it can do more than compare with regexes, read the linked docs to see its full potential):

#or any of the dozen other ways to tell 5.10 to use its new features
use feature qw/switch/; 

given($string) {
    when (/^abc/) { $abc     = 1; }
    when (/^def/) { $def     = 1; }
    when (/^xyz/) { $xyz     = 1; }
    default       { $nothing = 1; }
}

If you are using Perl 5.8 or earlier you must make do with if/elsif/else statements:

if    ($string =~ /^abc/) { $abc     = 1; }
elsif ($string =~ /^def/) { $def     = 1; }
elsif ($string =~ /^zyz/) { $xyz     = 1; }
else                      { $nothing = 1; }

or nested condition operators (?:):

$string =~ /^abc/ ? $abc     = 1  :
$string =~ /^def/ ? $def     = 1  :
$string =~ /^xyz/ ? $xyz     = 1  :
                    $nothing = 1;

There is a module in Core Perl (Switch) that gives you fake switch statements via source filters, but it is my understanding that it is fragile:

use Switch;

switch ($string) {
    case /^abc/ {
    case /^abc/ { $abc     = 1 }
    case /^def/ { $def     = 1 }
    case /^xyz/ { $xyz     = 1 } 
    else        { $nothing = 1 }
}

or the alternate syntax

use Switch 'Perl6';

given ($string) {  
    when /^abc/ { $abc     = 1; }
    when /^def/ { $def     = 1; }
    when /^xyz/ { $xyz     = 1; }
    default     { $nothing = 1; }
}

Upvotes: 59

Nathan Fellman
Nathan Fellman

Reputation: 127538

The suggestion in Programming Perl is:


for ($string) {
    /abc/ and do {$abc    = 1; last;};
    /def/ and do {$def    = 1; last;};
    /xyz/ and do {$xyz    = 1; last;};
    $nothing = 1;
}

Upvotes: 21

Related Questions