2
\$\begingroup\$

I know Perl now has given and when to simulate switch/case statements, but these are still experimental and are not guaranteed to be in future versions. Also there was a Switch module for Perl that existed in older versions, but it used source filtering and was considered not very good either so it went away.

Because of this, I decided to write my own module to simulate switch/case statements.

package Switch;

# Always use these
use strict;
use warnings;

# Imported modules
use Carp;

# Exporter
use Exporter qw(import);
our @EXPORT = qw(switch case break);

# Variable used to break out of the switch statement
my $BREAK;

sub switch {
    my $switch = shift;
    my @cases  = @_;

    # Check that each case has a function associated with it
    if (scalar @cases % 2) {
        croak "Invalid format in switch statement";
    }

    # Initialize BREAK
    $BREAK = 0;

    # Loop through each case
    while (my ($case, $code) = splice @cases, 0, 2) {

        # Check that $code is a code reference
        if (ref $code ne 'CODE') {
            $case = ref 'ARRAY' ? join ', ', @{$case} : $case;
            croak "case($case) does not have a valid function";
        }

        # Handle the default case
        if ($case eq 'default') { $code->(); next; }

        # Handle all other cases
        for (@{$case}) {
            $code->() if $_ eq $switch;
        }

        # Exit loop if BREAK is true
        last if $BREAK;
    }
}

# Construct an array reference of cases
sub case {
    return \@_;
}

# BREAK from the switch statement
sub break {
    $BREAK = 1;
}

1;

__END__

=head1 NAME

Switch - switch statements for Perl.

=head1 VERSION

$Revision: 1.1 $

=head1 SYNOPSIS

  use Switch;

  # Define a switch variable
  $switch = 3;

  # Implement a simple switch statement
  switch($switch,
      case(1)    => sub { print "\$switch = 1\n";      break; },
      case(2, 3) => sub { print "\$switch = 2 or 3\n";        },
      case(3)    => sub { print "\$switch = 3\n";      break; },
      default    => sub { print "default\n";                  },
  );

=head1 DESCRIPTION

The Switch module is designed to implement C-style switch statements in Perl.  The provided
switch variable will be tested against each case and will execute any/all matching cases until all
cases are tested or a break is encountered.

I have included some simple POD documentation that describes the usage.

To me the syntax looks quite elegant (it was the best I could do without using some sort of source filter myself).

What do you think?

What could be Improved?

\$\endgroup\$
  • \$\begingroup\$ $code->() if $_ eq $switch; Just to clarify, you're testing for hard equality, not the possibility of a regex/range/etc? If so, a hash might be a better choice. \$\endgroup\$ – Barry Carter Apr 29 '16 at 18:55
  • \$\begingroup\$ Yes, I am but I was thinking I may want to add regex capabilities in the future. The way it is now a hash may be a better implementation. \$\endgroup\$ – tjwrona1992 May 1 '16 at 23:44
  • \$\begingroup\$ My sense (perhaps incorrect) is that you could use 'eval' to combine many of these cases. \$\endgroup\$ – Barry Carter May 3 '16 at 2:40
  • \$\begingroup\$ My immediate thoughts are that comments like # Always use these, # Exporter, and # Imported modules are just nuisances that clouds the code. The ideal is for a program to be written so that it needs no comments at all \$\endgroup\$ – Borodin Jun 6 '16 at 0:03
  • \$\begingroup\$ You're right. Those comments are probably unnecessary, but I do feel like even very well written code should be commented to an extent. Especially when using advanced features of a language that newcomers might not recognize. \$\endgroup\$ – tjwrona1992 Jun 6 '16 at 2:57

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.