The T-Files


Sat, 07 Apr 2007

The thousand and one reasons to love Perl: [19] Switch

Starting with Perl 5.9.3, Perl finally has an official switch statement (in versions before there have been various hacks to emulate it, none of them pretty). The long wait has paid off, the Perl version is packed with dwimmery ("do what I mean").

/* C switch statement */
switch (data) {
	case 1:  printf ("one\n"); 
	         break;
	case 2:  printf ("two\n"); 
	         break;
	default: printf ("something else\n");
	         break;
}

In order to use post-5.8 features you have to enable them with the new feature pragma. This assures that the new keywords do not conflict with existing code. The keywords are not called switch and case, but given and when. A straightforward translation of above C code (also using the new say function, which is Perl's println) is the following:

use feature qw( switch say);

given($data) {
	when (1) { say 'one' ; break; };
	when (2) { say 'two' ; break; };
	default  { say 'something else'; break; };
}

The first improvement that has been made is to make the break optional. Whereas C and Java will fall through to the next option, which is usually not what you want, Perl will break out by default.

given($data) {
	when (1) { say 'one' ; };
	when (2) { say 'two' ; };
	default  { say 'something else';  };
}

Conversely, you cannot get the C behaviour of falling through to the next option. There is a continue keyword, which will go to the next when, but that condition will still be checked.

# this code does not work !
# it will say "something else"
given($data) {
	when (1) { continue; };
	when (2) { say 'one or two' ; };
	default  { say 'something else';  };
}

But the when clause is quite smart and can do more than simple literal comparisons, letting you say

# this works
given($data) {
	when ([ 1, 2]) { say 'one or two' ;  };
	default  { say 'something else';  };
}

This smart matching feature supports many different types of comparisons and it can also be used outside of when using the new ~~ operator.

Finally, you can combine the switch with a loop:

my $count = 0;
for (@array) {
   when ("foo") { ++$count }
}
say "\@array contains $count copies of 'foo'";