Perl Subroutines

Subroutines are used to divide your program into smaller more manageable modules. A subroutine is a separate body of code that performs a specific task Subroutines serve two purposes

Defining sub salaryCheck {
   if ( $salary > 50000)
   {
      print("You are promoted to manager\n");
   }
}
Invoking

#####################
## salaryCheck SUB ##
#####################
sub salaryCheck {
   if ( $salary > 50000)
   {
      print("You are promoted to manager and required to work 20 hours more\n");
   }
}

#####################
##      MAIN       ##
#####################
$salary = 60000;

print("Checking your salary\n");
&salaryCheck;

Note: the comments making it clear where the subroutines are, this helps any programmer when he/she has to change your code.

You use the keyword sub to define a subroutine, it does not matter where in the program you define your subroutine (I personally like to put subroutines at the top, that's just me). You use the & (ampersand) followed by the name of the subroutine to invoke a subroutine, the & tells the perl interpreter that the following name is a subroutine. You can remove the & (ampersand) when calling the subroutine only if the subroutines has been defined already ( I personally use the & (ampersand)).

remove & (ampersand) when invoking a subroutine

salaryCheck;                      ## This would fail as the subroutine has not been defined yet
                                  ## Now you know why i like putting subroutines at the top

#####################
## salaryCheck SUB ##
#####################
sub salaryCheck {
   if ( $salary > 50000)
   {
      print("You are promoted to manager and required to work 20 hours more\n");
   }
}

#####################
##      MAIN       ##
#####################
$salary = 60000;

print("Checking your salary\n");
salaryCheck;                       ## LOOK no & (ampersand)

Note: you can only obmit the & (ampersand) if the subroutines are defined before calling them

Returning a value from a Subroutine

The last value of the last expression evaluated by the subroutine is automatically considered to be the subroutine's return value

Subroutines return value ####################
## getNumbers SUB ##
####################
sub getNumbers
{
   $line = <STDIN>;
   $line =~ s/^\s+|\s*\n$//g;
   split(/\s+/, $line);         ## this is the return value
}

####################
####    Main    ####
####################
$total = 0;
foreach $number (&getNumbers)      ## can even call subroutines from the for loop
{
   $total += $number;
}
print ("\nThe total is: $total\n");

Return statement ####################
## getDummy SUB ##
####################
sub getDummy
{
   $dummy_value = 1000000;
   $line = <STDIN>;
   $line =~ s/^\s+|\s*\n$//g;
   split(/\s+/, $line);
   return $dummy_value;      ## We return a value other than the last expression value
}

####################
####    Main    ####
####################
print ("\nThe dummy_value is " . &getDummy );

Note: we can use the keyword return to return a different value than the last expression

Local Variables

There are two statements that define local variables

my

####################
### localVar SUB ###
####################
sub localVar
{
   my $total = 100;        ## defining a local variable with my keyword
   return $total;
}

##################
###    Main    ###
##################
$total = 10;
print ("Local total is $total\n");
print ("Subroutine local total is " . &localVar)

local you can use local keyword instead of the my keyword. The only difference between the two is that my variables are not know outside the subroutine.

Passing values to a subroutine

You make subroutines more flexible by allowing them to accept values passed from the main or any other subroutine program; these values passed are known as arguments. When passing the arguments to a subroutine they are placed in the system array variable @_, it is create whenever you pass arguments to a subroutine.

Passing values to subroutines

########################
## whoDoYouupport SUB ##
########################
sub whoDoYouSupport
{
my ($team, $home, $crowd) = @_;        # place the passed arguments into local variables getting them
                                       # from the system array variable @_

print("Team: $team\n");
print("Home Ground: $home\n");
print("Capacity: $crowd\n");

print ("system array variable first element is " . $_[0]);    # acts just like any normal array
}

##################
###    Main    ###
##################
$footballTeam = "Milton Keynes Dons";
$ground = "MK Stadium";
$capacity = 30000;

&whoDoYouSupport($footballTeam, $ground, $capacity);   # pass the arguments to the subroutine

Passing lists to subroutines #####################
###  getLists SUB ###
#####################
sub getLists
{
   my (@localList) = @_;           # all the lists will be merged into a single array @_

   foreach $number (@localList)
   {
      print("$number\n");
   }
}

##################
###    Main    ###
##################
$num_one = 1;
@num_list = qw( 2 3 4 5);
$num_six = 6;

&getLists($num_one, @num_list, $num_six);      # pass all the lists as arguments

Calling subroutines from subroutines

####################
### routine1 SUB ###
####################
sub routine1 {
   &routine2;    # call subroutine routine2
}

####################
### routine2 SUB ###
####################
sub routine2 {
   print("You called subroutine two from subroutine one\n");
}

##################
###    Main    ###
##################
&routine1;

Recursive subroutines

#####################
### rightcalc SUB ###
#####################
sub rightcalc {
   my ($index) = @_;
   my ($result, $operand1, $operand2);

   if ( $index+3 == @list )
   {
      $operand2 = $list[$index2+2];
   }
   else
   {
      $operand2 = &rightcalc($index+2);
   }
   $operand1 = $list[$index+1];
   if ($list[$index] eq "+" )
   {
      $result = $operand1 + $operand2;
   }
   elsif ($list[$index] eq "*" )
   {
      $result = $operand1 * $operand2;
   }
   elsif ($list[$index] eq "-" )
   {
      $result = $operand1 - $operand2;
   }
   else
   {
      $result = $operand1 / $operand2;
   }
}

##################
###    Main    ###
##################
$inputline = <STDIN>;$inputline =~ s/^\s+|\s+$//g;
@list = split(/\s+/, $inputline);
$result = &rightcalc(0);
print ("The result is $result\n");

Passing arrays by name using aliases

##################
###  my_sub    ###
##################
sub my_sub {
   local (*subarray) = @_;      # tells the perl interpreter to operate on the actual list

   foreach $number (@subarray) {
      print($number . "\n");
   }
}

##################
###    Main    ###
##################
@list = qw( 1 2 3 4 5);
&my_sub(*list);                 # the argument *foo indicates that the array @foo is to be passed to
                                # my_sub and aliased

BEGIN and END subroutines

exit;
print("should not see this as it is after exit statement\n");
BEGIN { print("This will always execute\n") };
END { print("This will also always execute even you you stop the program with die or exit\n")};

AUTLOAD (non-existent subroutines

@list = qw( 1 2 3 4);
&crazysun(@list);

AUTOLOAD { print("subroutine $AUTOLOAD does not exist check your code\n"); }

Note: useful if you have very large scripts or have many perl modules