Learning Perl - Subroutines


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.

Related Blogs

Learning Perl – Introduction
Perl has long been known as the “duct tape of the Internet,” or "the Swiss Army chainsaw of scripting...
Learning Perl - Variables
I will attempt to explain things in this post in a way that is easy to understand, even for those who...
Learning Perl - Arrays
As stated in the previous post, Perl has three types of variables: scalars, arrays and hashes. Today...
Learning Perl - Hashes
In the last post we covered the basics of arrays, today we will look at hashes in more detail. What...
Learning Perl - Conditional Statements
So far we have covered basic variables in Perl, today we are going to look at how to use these...
Learning Perl - Loops and Iteration
In previous posts, we explored variables, arrays, hashes, and conditional statements in Perl. Now...
Learning Perl - Scalars
Before moving onto more complex topics lets come back to how we represent data in Perl. The most...
Learning Perl - References
In the last post we learnt how to create a reference to a scalar, an array, and a hash. In this post,...
Learning Perl - Ternary Operators
In a previous post, we learned about conditional statements in Perl. The ternary operator is an...
Learning Perl - Regular Expressions
Regular expressions also known as regex or regexp, are a powerful way to match patterns in text. Most...
Learning Perl - Modules
A module in Perl is a reusable piece of code that can be included in your scripts to provide...
Learning Perl - CPAN
In the last post I showed you how to create a new module and how to use it in your code. In this post...
Learning Perl - Plain Old Documentation
When you write and program in any language it is good practice to document your code. Each language...
Learning Perl - Testing
In this post we will look at how to test Perl code using the Test::More module. Like documentation,...
Learning Perl - Exporting
In programming, we often want to share functionality across different parts of our code. In Perl,...
Learning Perl - Object Orientation
Object-Oriented Programming (OOP) is a widely used programming paradigm that enables the creation of...
Learning Perl - Inheritance
In the last post we discussed Object Oriented Programming in Perl, focusing on the basics of creating...
Learning Perl - File Handles
In programming file processing is a key skill to master. Files are essential for storing data,...
Learning Perl - Prototypes
Today we are going to discuss Perl subroutine prototypes, which are a way to enforce a certain...
Learning Perl - Overloading Operators
In the last post we investigated prototype subroutines in Perl. In this post, we will look at...