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: 30Parameter 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); # 8Using my to Get Parameter Copies
perl
sub multiply {
my ($a, $b) = @_; # Assign parameters to local variables
return $a * $b;
}
print multiply(4, 5); # 20Modifying 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 6Return 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: 5Implicit 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(); # 20Returning 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: 5Default 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); # 120Recursion 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 34Recursion 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->(); # 3Prototypes
Basic Prototype
perl
sub add($$) { # Accept two scalars
my ($a, $b) = @_;
return $a + $b;
}
print add(10, 20); # 30Array 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); # 15Hash 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:
- ✅ Defining and calling subroutines
- ✅ Parameter passing
- ✅ Return values
- ✅ Default parameters
- ✅ Named parameters
- ✅ Recursion
- ✅ Anonymous subroutines
- ✅ Prototypes
Next, we will learn Perl References.