Switching up my switches in Perl
Tags: programming, perl
Published: 2021-02-14 23:41:30

---
title: Switching up my switches in Perl
published: true
date: 2021-02-14 23:17:52 UTC
tags: Programming,Perl
canonical_url: https://phoenixtrap.com/2021/02/14/switching-up-my-switches/
---

Pretty soon after I started writing Perl in 1994, I noticed that it lacked a construct often found in other languages: the [switch statement](https://en.wikipedia.org/wiki/Switch_statement). Not to worry, though—you can achieve the same effect with a cascading series of [`if`-`elsif`](https://perldoc.pl/perlsyn#Compound-Statements) statements, right?

Well, no, you shouldn’t do that, especially if the chain is really long. There’s even a [perlcritic policy](https://metacpan.org/pod/Perl::Critic::Policy::ControlStructures::ProhibitCascadingIfElse) about it, which suggests that you use [`given` and `when`](https://perldoc.pl/perlsyn#Switch-Statements) instead.

But `given` and `when` (and the [smartmatch operator](https://perldoc.pl/perlop#Smartmatch-Operator) they imply, `~~`) are still considered [experimental](https://perldoc.pl/perlsyn#Experimental-Details-on-given-and-when), with behavior subject to change. So what’s a responsible developer to do?

The answer is to use the `for` statement as a _topicalizer_, which is a fancy way of saying it assigns its expression to [`$_`](https://perldoc.pl/variables/%24_). You can then use things that act on `$_` to your heart’s content, like regular expressions. Here’s an example:

```perl
for ($foo) {
    /^abc/ and do {
        ...
        last;
    };
    /^def/ and do {
        ...
        last;
    };
    # FALL THRU
    ...
}
```

This will cover a lot of cases (haha, see what I did there? A lot of languages use a `case` statement… oh, never mind.) And if all you’re doing is exact string matching, there’s no need to bring in regexps. You can use a hash as a lookup table:

```perl
my %lookup = (
    foo => sub { ... },
    bar => sub { ... },
);
$lookup{$match}->();
```

**EDIT**: If every alternative is assigning to the same variable, a ternary table is another possibility. This is a chained set of [ternary conditional (`? :`)](https://perldoc.pl/perlop#Conditional-Operator) operators arranged for readability. I first heard about this technique from [Damian Conway's _Perl Best Practices_](https://learning.oreilly.com/library/view/perl-best-practices/0596001738/) (2005).

```perl
           # Name format                 # Salutation
my $salute = $name eq ''                 ? 'Dear Customer'
           : $name =~ /(Mrs?[.]?\s+\S+)/ ? "Dear $1"
           : $name =~ /(.*),\s+Ph[.]?D/  ? "Dear Dr. $1"
           :                               "Dear $name"
           ;
```

Note that although this is just as inefficient as a cascaded-`if`/`elsif`, it’s more clear that it's a single assignment. It’s also more compact and reads like a table with columns of matches and alternatives.

Any of these patterns are preferable to cascading `if`/`elsif`s. And if you want to monitor the development of `given`, `when`, and `~~`, check [this issue on GitHub](https://github.com/Perl/perl5/issues/13173). It was last commented on eight years ago, though, so I wouldn’t hold my breath.