DEV Community

Cover image for Learning Perl - Subroutines
LNATION for LNATION

Posted on • Edited on

Learning Perl - Subroutines

Subroutines are one of the most important building blocks in programming. They allow you to organise your code into reusable pieces, making your scripts and modules easier to read, maintain, and extend. A subroutine is a block of code that performs a specific task. You can call a subroutine from anywhere in your program, and you can even call it multiple times with different arguments.

In Perl a subroutine can be named, these are usually known as functions or methods depending on the context of your code, or anonymous, which in perl we call code references. Named subroutines are defined using the 'sub' keyword followed by the subroutine name and a block of code. Anonymous subroutines are defined without a name and can be assigned to a variable or passed as an argument, anonymous subroutines also do not require the 'sub' keyword in certain cases. We have already seen some examples of anonymous subroutines in the previous chapters, such as when we used 'map' and 'grep'.

Let's look at some examples of subroutines, first a named subroutine, these are what we call 'functions' in Perl as we are not dealing with object-oriented programming at this point.

sub greet {
    my $name = shift;  # Get the first argument passed to the subroutine
    print "Hello, $name!\n";
}
Enter fullscreen mode Exit fullscreen mode

You would then call this subroutine function like this:

greet("Rupert");  # Output: Hello, Rupert!
Enter fullscreen mode Exit fullscreen mode

As you can see, the 'greet' subroutine takes one argument (the name) and prints a greeting message. The 'shift' keyword retrieves the first argument passed to the subroutine.

If you were to rewrite the 'greet' subroutine to an anonymous subroutine, it would look like this:

my $greet = sub {
    my $name = shift;  # Get the first argument passed to the subroutine
    print "Hello, $name!\n";
};
Enter fullscreen mode Exit fullscreen mode

You can call the anonymous subroutine like this:

$greet->("Rupert");  # Output: Hello, Rupert!
Enter fullscreen mode Exit fullscreen mode

You can also pass multiple arguments to subroutines. You do this by passing a list to the subroutine, this can either be an 'array' or a 'hash' and you can access the elements of the list using the '@_' array, which is a special array that contains all the arguments passed to the subroutine.

sub add {
    my (@array) = @_;
    return $array[0] + $array[1];    # Return the sum of the two arguments
}
Enter fullscreen mode Exit fullscreen mode

You can call this subroutine like this:

my $sum = add(3, 5);  # Output: 8
Enter fullscreen mode Exit fullscreen mode

We can also unpack the arguments directly into scalar variables:

sub add {
    my ($a, $b) = @_;  # Unpack the first two arguments into $a and $b
    return $a + $b;    # Return the sum of the two arguments
}
Enter fullscreen mode Exit fullscreen mode

When dealing with hashes, you can also unpack the arguments directly into hash variables:

sub print_person {
    my (%person) = @_;  # Unpack the hash into %person
    print "Name: $person{name}, Age: $person{age}\n";
}
Enter fullscreen mode Exit fullscreen mode

You can call this subroutine like this:

print_person(name => "Alice", age => 30);  # Output: Name: Alice, Age: 30
Enter fullscreen mode Exit fullscreen mode

In this case you probably don't want to use individual variables, but rather use the hash directly however you can do it like this:

sub print_person {
    my ($key1, $value1, $key2, $value2) = @_;  # Unpack the hash into individual variables
    print "Name: $value1, Age: $value2\n";
}
Enter fullscreen mode Exit fullscreen mode

An anonymous subroutine can also be used to create something we call closures in programming, which is a subroutine that captures the lexical variables from its surrounding scope. This allows you to create subroutines that have their own private state.

my $make_counter = sub {
    my $count = 0;  # Lexical variable to hold the count

    return sub {  # Return an anonymous subroutine
        $count++;  # Increment the count
        return $count;  # Return the current count
    };
};
Enter fullscreen mode Exit fullscreen mode

You would then create a counter like this:

my $counter = $make_counter->();  # Create a new counter
Enter fullscreen mode Exit fullscreen mode

And you can call the counter like this:

# You can call the counter like this:
print $counter->();  # Output: 1
print $counter->();  # Output: 2
Enter fullscreen mode Exit fullscreen mode

Okay on with a basic example, today we will build our first subroutine, which will be a simple calculator that can add, subtract, multiply, and divide two numbers. We will use a single named subroutine that handles all four operations based on the operation passed as an argument. Usually you would have a separate subroutine for each operation as it is good practice for a subroutine to do one particular task but for today our subroutine will perform multiple tasks. Create a new file called 'calculator.pl' and add the following code:

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

sub calculator {
    my ($operation, $num1, $num2) = @_;  # Unpack the arguments

    if ($operation eq 'add') {
        return $num1 + $num2;  # Return the sum
    } elsif ($operation eq 'subtract') {
        return $num1 - $num2;  # Return the difference
    } elsif ($operation eq 'multiply') {
        return $num1 * $num2;  # Return the product
    } elsif ($operation eq 'divide') {
        return $num1 / $num2;  # Return the quotient
    } else {
        die "Unknown operation: $operation";  # Handle unknown operations
    }
}
Enter fullscreen mode Exit fullscreen mode

Then at the end of the file, you can add some test cases to see how the calculator works:

print "Addition: ", calculator('add', 10, 2), "\n";
print "Multiplication: ", calculator('multiply', 4, 3), "\n";
print "Subtraction: ", calculator('subtract', 8, 5), "\n";
print "Division: ", calculator('divide', 20, 4), "\n";
Enter fullscreen mode Exit fullscreen mode

The code should be self explanatory, but let's break it down a bit. The 'calculator' subroutine takes three arguments: the operation to perform and the two numbers to operate on. It uses a series of conditional statements to determine which operation to perform and returns the result. If an unknown operation is passed, it dies with an error message. You can run this script from the command line to see the output of the calculator.

To run the script, use the following command:

perl calculator.pl
Enter fullscreen mode Exit fullscreen mode

Output:

Addition: 12
Multiplication: 12
Subtraction: 3
Division: 5
Enter fullscreen mode Exit fullscreen mode

With that working, you have written your first subroutine in Perl! Subroutines are a powerful feature of Perl that allow you to organise your code and make it more reusable. As you continue to learn Perl, you'll find that subroutines are an essential part of writing clean and maintainable code.

If you have any questions or need further clarification, feel free to ask! Next time we will look at basic regular expressions, which are a powerful way to match and manipulate strings. Regular expressions are a bit more advanced, but they are an essential tool in Perl for text processing.

Top comments (0)

Some comments may only be visible to logged-in visitors. Sign in to view all comments.