Perl has no switch statements. How do I avoid a long if-else-if pattern?

The problem:

You have some conditional behaviour that depends on the value of a variable, for example, a user's selection of a menu.

    #!/usr/bin/perl
    use strict;
    use warnings;

    # Subroutine prototypes
    sub do_exit();
    sub query_account_status();
    sub process_direct_deposits();

    # Print the menu selection
    print <<"EOT";
    Select one of:
    1. Process Direct Deposists
    2. Query account status
    3. Exit
    EOT

    # Get the user's input
    my $menu_item = <>;

    # Take action based on the user's choice
    if ($menu_item == 1) {
        process_direct_deposits();
    } elsif ($menu_item == 2) {
        query_account_status();
    } elsif ($menu_item == 3) {
        do_exit();
    } else {    
        print "I didn't understand the command.\n";
        do_exit();
    }

    exit 0;

    #-------------------------------------------------------------
    # Subroutines
    sub process_direct_deposits() {
        print "Processing direct deposits\n";
        return;
    }

    sub query_account_status() {
        print "Querying account status\n";
        return;
    }

    sub do_exit() {
        print "Exiting...\n";
        return;
    }

Solution: Hashes!

A neat way to avoid the problem is to use a hash.

Use subroutine references in a hash to define what to do for each case:

    my $action_to_take = (    
        1 => \&process_direct_deposits,
        2 => \&query_account_status,
        3 => \&do_exit,
    );

Then where your if statements would be, simply call the subroutine:

    if (defined $action_to_take{$menu_item}) {
        $action_to_take{$menu_item}->();
    } else {
        print "I didn't understand the command.\n";
        do_exit();
    }

While for this small example, the amount of code saved is not staggering, to include extra cases you only need to add entries to the 'action_to_take' hash, rather than create a whole new section to the if statement.

It also means that you can build the hash in another subroutine and call it somewhere else.

The full example follows:

    #!/usr/bin/perl
    use strict;
    use warnings;

    # Subroutine prototypes
    sub do_exit();
    sub query_account_status();
    sub process_direct_deposits();

    # Define the actions to take
    my %action_to_take = (
        '1' => \&process_direct_deposits,
        '2' => \&query_account_status,
        '3' => \&do_exit,
    );

    # Print the menu selection
    print <<"EOT";
    Select one of:
    1. Process Direct Deposists
    2. Query account status
    3. Exit
    EOT

    # Get the user's input
    my $menu_item = <>;
    chomp($menu_item);

    # Take action based on the user's choice
    if (defined $action_to_take{$menu_item}) {
        $action_to_take{$menu_item}->();
    } else {
        print "I didn't understand the command.\n";
        do_exit();
    }

    exit 0;

    #-------------------------------------------------------------
    sub process_direct_deposits() {
        print "Processing direct deposits\n";
        return;
    }

    sub query_account_status() {
        print "Querying account status\n";
        return;
    }

    sub do_exit() {
        print "Exiting...\n";
        return;
    }
Revision: 1.3 Reviewed:  

[Top]