I will first mention the standard way to report bugs in Perl, perlbug.

I hadn’t used it before yesterday. I used it twice yesterday.

Because perldoc feature says this:

The ‘switch’ feature

WARNING: because the smartmatch operator is experimental, Perl will warn when you use this feature, unless you have explicitly disabled the warning:

no warnings "experimental::smartmatch";

use feature 'switch' tells the compiler to enable the Perl 6 given/when construct.

I thought that was bad documentation. Smart match is an interesting idea: 42 != 42.0 != "42", but shouldn’t they? That’s the idea.

The implementation is …

(Just about everything I currently know about smartmatch, I learned in the last 24 hours, trying to understand switch.)

So, thinking “That must be faulty documentation”, I used perlbug and then wrote

use strict;
use warnings;
use feature qw{ say switch };

for my $foo ( 1, 2, 'abc', '', undef ) {
    say qq{+\tFOO = $foo };
    given ($foo) {
        when (1) { say qq{foo == 1 } }
        when ( [ 2, 3 ] ) { say qq{foo3==2||foo==3} }
        when (/^a/) { say 'Foo starts with "a"' }
        default     { say 'NOTA' }
    }
}

And got:

given is experimental at /home/jacoby/switch.pl line 10.
when is experimental at /home/jacoby/switch.pl line 11.
when is experimental at /home/jacoby/switch.pl line 12.
when is experimental at /home/jacoby/switch.pl line 13.
+	FOO = 1
foo == 1
+	FOO = 2
foo3==2||foo==3
+	FOO = abc
Argument "abc" isn't numeric in smart match at /home/jacoby/switch.pl line 11.
Foo starts with "a"
+	FOO =
Argument "" isn't numeric in smart match at /home/jacoby/switch.pl line 11.
NOTA
Use of uninitialized value $foo in concatenation (.) or string at /home/jacoby/switch.pl line 9.
+	FOO =
Use of uninitialized value $_ in pattern match (m//) at /home/jacoby/switch.pl line 13.
NOTA

no warnings qw{ experimental::switch } doesn’t exist, so the operators in switch are in experimental::smartmatch.

🤷

Once I realized that, while not well-written, the warning in the POD is correct, I made another perlbug ticket, saying that moving given and when to experimental::switch is perhaps the better choice.

You can do this pretty much with if:

for my $foo ( 1, 2, 'abc', '', undef ) {
    say qq{+\tFOO = $foo };
    if ( $foo == 1 ) { say qq{foo == 1 } }
    elsif ( $foo == 2 || $foo == 3 ) { say qq{foo3==2||foo==3} }
    elsif ( $foo =~ /^a/ ) { say 'Foo starts with "a"' }
    else                   { say 'NOTA' }
}
+	FOO = 1
foo == 1
+	FOO = 2
foo3==2||foo==3
+	FOO = abc
Argument "abc" isn't numeric in numeric eq (==) at /home/jacoby/switch.pl line 21.
Foo starts with "a"
+	FOO =
Argument "" isn't numeric in numeric eq (==) at /home/jacoby/switch.pl line 21.
NOTA
Use of uninitialized value $foo in concatenation (.) or string at /home/jacoby/switch.pl line 20.
+	FOO =
Use of uninitialized value $foo in numeric eq (==) at /home/jacoby/switch.pl line 21.
Use of uninitialized value $foo in numeric eq (==) at /home/jacoby/switch.pl line 22.
Use of uninitialized value $foo in numeric eq (==) at /home/jacoby/switch.pl line 22.
Use of uninitialized value $foo in pattern match (m//) at /home/jacoby/switch.pl line 23.
NOTA

(Clearly, it’s best to always put the same kind of values through, rather than random types.)

I don’t know if you can really call this a switch without fallthrough.

//https://en.wikipedia.org/wiki/Switch_statement

switch (age) {
    case 1:     printf("You're one.") ; break;
    case 2:     printf("You're two.") ; break;
    case 3:     printf("You're three.") ;
    case 4:     printf("You're three or four.") ; break;
    default:    printf("You're not 1,2,3 or 4.") ;
}

Notice case 3: has no break, which means that three also executes, so, running 3 through it would get you:

You're three.
You're three or four.

(Maybe on the same line? I don’t use C often.)

There is at least one algorithm that did a thing with fallthrough, but I cannot find it, and when my 20-years-younger mind read that code, it just boggled. Much harder than the Schwarzian Transform, which I eventually understood.

Perl can do that. Of course Perl can do that.

for my $age ( 1 .. 5 ) {
    say qq{+ Jeffty is $age };
    given ($age) {
        when (1) { say "You're one."; }
        when (2) { say "You're two."; }
        when (3) { say "You're three."; continue; }
        when (4) { say "You're three or four."; }
        default  { say "You're not 1,2,3 or 4."; }
    }
    say '';
}

# + Jeffty is 1
# You're one.
#
# + Jeffty is 2
# You're two.
#
# + Jeffty is 3
# You're three.
# You're not 1,2,3 or 4.
#
# + Jeffty is 4
# You're three or four.
#
# + Jeffty is 5
# You're not 1,2,3 or 4.

So, I could use that.

This is not what I do these days, though.

What I normally do is use a dispatch table:

my $table;
$table->{1}       = sub { say "You're one." };
$table->{2}       = sub { say "You're two." };
$table->{3}       = sub { say "You're three." };
$table->{4}       = sub { say "You're three or four." };
$table->{default} = sub { say "You're not 1,2,3 or 4." };

# I don't need fallthrough
for my $age ( 1 .. 5 ) {
    say qq{+ Jeffty is $age };
    if ( defined $table->{$age} ) {
        $table->{$age}->()
    }
    else { $table->{default}->() }
}

I could imagine a case when I reach for a switch, but I’m satisfied with either the table or stacked if/elsif/else statements, depending. I’m willing to start, if there’s an argument for it, but right now, I just don’t see it.

If you have any questions or comments, I would be glad to hear it. Ask me on Twitter or make an issue on my blog repo.