Skip to content

Perl Subroutines (Functions)

Defining Subroutines

Basic sub Definition

perl
sub greet {
    print "Hello, World!\n";
}

# Call subroutine
greet();

Subroutine with Parameters

perl
sub greet_person {
    my ($name) = @_;
    print "Hello, $name!\n";
}

greet_person("Alice");
greet_person("Bob");

Multiple Parameters

perl
sub add_numbers {
    my ($a, $b) = @_;
    return $a + $b;
}

my $result = add_numbers(10, 20);
print "Result: $result\n";  # Result: 30

Parameter Passing

Using @_

@_ is a special array containing all parameters:

perl
sub print_params {
    print "Number of parameters: " . scalar(@_) . "\n";
    foreach my $param (@_) {
        print "Parameter: $param\n";
    }
}

print_params("apple", "banana", "orange");

Accessing Parameters Directly

perl
sub add {
    my $sum = $_[0] + $_[1];
    return $sum;
}

print add(5, 3);  # 8

Using my to Get Parameter Copies

perl
sub multiply {
    my ($a, $b) = @_;  # Assign parameters to local variables
    return $a * $b;
}

print multiply(4, 5);  # 20

Modifying Original Parameters

perl
sub modify_array {
    my ($arr_ref) = @_;  # Receive array reference
    foreach my $elem (@$arr_ref) {
        $elem *= 2;
    }
}

my @numbers = (1, 2, 3);
modify_array(\@numbers);
print "@numbers\n";  # 2 4 6

Return Values

Using return

perl
sub divide {
    my ($a, $b) = @_;
    return $a / $b if $b != 0;
    return undef;  # Return undef when dividing by zero
}

my $result = divide(10, 2);
print "Result: $result\n";  # Result: 5

Implicit Return

The value executed last in the subroutine is automatically returned:

perl
sub implicit_return {
    my $x = 10;
    $x * 2;  # Returns 20
}

print implicit_return();  # 20

Returning Multiple Values

perl
sub get_stats {
    my @numbers = @_;
    my $sum = 0;
    my $min = $numbers[0];
    my $max = $numbers[0];
    
    foreach my $num (@numbers) {
        $sum += $num;
        $min = $num if $num < $min;
        $max = $num if $num > $max;
    }
    
    return ($sum, $min, $max);
}

my ($total, $minimum, $maximum) = get_stats(1, 5, 3, 9, 2);
print "Sum: $total, Min: $minimum, Max: $maximum\n";

Returning Lists and Scalars

perl
sub get_data {
    return (1, 2, 3, 4, 5);
}

# List context
my @data = get_data();
print "@data\n";  # 1 2 3 4 5

# Scalar context
my $count = get_data();
print "Count: $count\n";  # Count: 5

Default Parameters

Using // for Default Values

perl
sub greet_with_default {
    my ($name, $greeting) = @_;
    $name //= "World";
    $greeting //= "Hello";
    print "$greeting, $name!\n";
}

greet_with_default();              # Hello, World!
greet_with_default("Alice");        # Hello, Alice!
greet_with_default("Bob", "Hi");    # Hi, Bob!

Using || for Default Values (Be Careful)

perl
sub multiply {
    my ($a, $b) = @_;
    $a ||= 1;
    $b ||= 1;
    return $a * $b;
}

print multiply();        # 1
print multiply(5);      # 5
print multiply(5, 0);   # 5 (0 replaced with 1)

Named Parameters

Using Hashes for Named Parameters

perl
sub create_user {
    my %params = @_;
    my $name = $params{name} // "Anonymous";
    my $age = $params{age} // 0;
    my $email = $params{email} // "";
    
    return {
        name => $name,
        age => $age,
        email => $email
    };
}

my $user1 = create_user(name => "Alice", age => 25);
my $user2 = create_user(email => "bob@example.com");

print "$user1->{name}, $user1->{age}\n";
print "$user2->{email}\n";

Using References for Named Parameters

perl
sub process_data {
    my ($data_ref, $options_ref) = @_;
    my $verbose = $options_ref->{verbose} // 0;
    
    if ($verbose) {
        print "Processing " . scalar(@$data_ref) . " items\n";
    }
    
    return [map { $_ * 2 } @$data_ref];
}

my @numbers = (1, 2, 3);
my $result = process_data(\@numbers, {verbose => 1});
print "@$result\n";

Recursion

Basic Recursion Example: Factorial

perl
sub factorial {
    my ($n) = @_;
    return 1 if $n <= 1;
    return $n * factorial($n - 1);
}

print factorial(5);  # 120

Recursion Example: Fibonacci

perl
sub fibonacci {
    my ($n) = @_;
    return $n if $n <= 1;
    return fibonacci($n - 1) + fibonacci($n - 2);
}

for (my $i = 0; $i < 10; $i++) {
    print fibonacci($i) . " ";
}
# 0 1 1 2 3 5 8 13 21 34

Recursion Example: Tower of Hanoi

perl
sub hanoi {
    my ($n, $from, $to, $aux) = @_;
    return if $n == 0;
    
    hanoi($n - 1, $from, $aux, $to);
    print "Move disk $n from $from to $to\n";
    hanoi($n - 1, $aux, $to, $from);
}

hanoi(3, "A", "C", "B");

Anonymous Subroutines

Basic Anonymous Subroutine

perl
my $greet = sub {
    my ($name) = @_;
    print "Hello, $name!\n";
};

$greet->("World");

As Callback Function

perl
sub process_list {
    my ($list, $callback) = @_;
    foreach my $item (@$list) {
        $callback->($item);
    }
}

my @fruits = ("apple", "banana", "orange");
process_list(\@fruits, sub {
    my ($fruit) = @_;
    print "Fruit: $fruit\n";
});

Closure

perl
sub make_counter {
    my $count = 0;
    return sub {
        return ++$count;
    };
}

my $counter1 = make_counter();
my $counter2 = make_counter();

print $counter1->();  # 1
print $counter1->();  # 2
print $counter2->();  # 1
print $counter1->();  # 3

Prototypes

Basic Prototype

perl
sub add($$) {  # Accept two scalars
    my ($a, $b) = @_;
    return $a + $b;
}

print add(10, 20);  # 30

Array Prototype

perl
sub sum_array(\@) {  # Accept an array
    my ($arr_ref) = @_;
    my $total = 0;
    $total += $_ for @$arr_ref;
    return $total;
}

my @numbers = (1, 2, 3, 4, 5);
print sum_array(@numbers);  # 15

Hash Prototype

perl
sub print_hash(\%) {
    my ($hash_ref) = @_;
    while (my ($k, $v) = each %$hash_ref) {
        print "$k: $v\n";
    }
}

my %data = (a => 1, b => 2);
print_hash(%data);

Practice Examples

Example 1: Simple Calculator

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

sub add {
    my ($a, $b) = @_;
    return $a + $b;
}

sub subtract {
    my ($a, $b) = @_;
    return $a - $b;
}

sub multiply {
    my ($a, $b) = @_;
    return $a * $b;
}

sub divide {
    my ($a, $b) = @_;
    die "Cannot divide by zero" if $b == 0;
    return $a / $b;
}

print "Calculator\n";
print "Enter first number: ";
chomp(my $num1 = <STDIN>);

print "Enter second number: ";
chomp(my $num2 = <STDIN>);

printf "Addition: %.2f\n", add($num1, $num2);
printf "Subtraction: %.2f\n", subtract($num1, $num2);
printf "Multiplication: %.2f\n", multiply($num1, $num2);
printf "Division: %.2f\n", divide($num1, $num2);

Example 2: Data Validation

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

sub is_email {
    my ($email) = @_;
    return $email =~ /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/;
}

sub is_phone {
    my ($phone) = @_;
    return $phone =~ /^\d{3}-\d{3}-\d{4}$/;
}

sub validate_user {
    my ($name, $email, $phone) = @_;
    
    my @errors = ();
    
    push @errors, "Name is required" unless $name;
    push @errors, "Invalid email format" unless is_email($email);
    push @errors, "Invalid phone format" unless is_phone($phone);
    
    return @errors;
}

my $name = "Alice";
my $email = "alice@example.com";
my $phone = "123-456-7890";

my @errors = validate_user($name, $email, $phone);

if (@errors) {
    print "Validation errors:\n";
    print "- $_\n" for @errors;
} else {
    print "Validation passed!\n";
}

Example 3: Text Processing Tool

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

sub count_words {
    my ($text) = @_;
    my @words = split /\s+/, $text;
    return scalar @words;
}

sub count_chars {
    my ($text) = @_;
    return length($text);
}

sub count_lines {
    my ($text) = @_;
    my @lines = split /\n/, $text;
    return scalar @lines;
}

sub find_longest_word {
    my ($text) = @_;
    my @words = split /\s+/, $text;
    my $longest = "";
    
    foreach my $word (@words) {
        $longest = $word if length($word) > length($longest);
    }
    
    return $longest;
}

my $sample_text = "This is a sample text for demonstration purposes.
It contains multiple lines and words.";

printf "Words: %d\n", count_words($sample_text);
printf "Characters: %d\n", count_chars($sample_text);
printf "Lines: %d\n", count_lines($sample_text);
printf "Longest word: %s\n", find_longest_word($sample_text);

Summary

In this chapter, we learned Perl subroutines:

  1. ✅ Defining and calling subroutines
  2. ✅ Parameter passing
  3. ✅ Return values
  4. ✅ Default parameters
  5. ✅ Named parameters
  6. ✅ Recursion
  7. ✅ Anonymous subroutines
  8. ✅ Prototypes

Next, we will learn Perl References.

Content is for learning and research only.