1. Perl
  2. here

How to create a subroutine

Learn how to create a subroutine. A subroutine is a function that allows you to name and call a set of functions. It is the same as a function called a function in other languages. Perl builtin functions are explained in Perl builtin functions.

Subroutine definition

To define a subroutine:

sub Subroutine name {
  # process
}

As a simple subroutine, let's define a subroutine named total that finds the sum of two values.

sub total {
  # (1) Receiving arguments
  my ($num1, $num2) = @_;

  # (2) Processing
  my $total = $num1 + $num2;

  # (3) Return value
  return $total;
}

(1) The argument is stored in the variable " @_ ". I've reassigned the variable $num1 and $num2 to give the arguments descriptive names. (2) The two values are totaled. (3) The return value can be returned using return function.

Subroutine call

To call the subroutine: You can pass an argument and receive the processed result as a return value.

Return value = Subroutine (argument);

Now let's call the total function we created earlier.

use strict;
use warnings;

# (1) Value to be passed as an argument
my $num1 = 1;
my $num2 = 2;

# (2) Subroutine call
my $total = total ($num1, $num2);

# (3) Subroutine definition
sub total {
  my ($num1, $num2) = @_;

  my $total = $num1 + $num2;

  return $total;
}

(1) This is the value to be passed to the argument. (2) This is a subroutine call. The return value is assigned to $total. The result of adding 1 and 2 is returned, so $total is 3. (3) Subroutine definitions can also be placed under the call. This is because the subroutine definition is read at compile time.

Subroutine arguments

Explains how to receive subroutine arguments.

Receive one argument

A common way to receive a single argument is to use the shift function.

sub func {
  my $arg = shift;
}

When you call the shift function in a subroutine, "@_" is the implicit argument of the shift function. So the above is

sub func {
  my $arg = shift @_;
}

Will be the same as.

Receive multiple arguments

A commonly used method when receiving multiple arguments is list assignment.

sub func {
  my ($arg1, $arg2) = @_;
}

The first element of @_ is assigned to $arg1 and the second element is assigned to $arg2.

If the arguments are of the same type, they should be received in an array.

sub func {
  my @args = @_;
}

Access arguments directly

"@_" Is an array, but you can also access this array directly.

# First argument
$_[0]

# Second argument
$_[1]

This style of writing reduces readability and is recommended not to be used unless performance is absolutely necessary.

Pass an array as a subroutine argument

You can pass an array to a subroutine.

# Passing side
my $num_total = sum (@nums);

# Recipient
sub sum {
  my @nums = @_;
  # process
}

Pass a hash as a subroutine argument

You can also pass a hash to the subroutine. On the receiving side, @_ will be assigned to the hash. In Perl, the contents of an array are lists, so you can assign them to hashes.

# Passing side
my $examin_total = sum_examin (%examin);

# Recipient
sub sum_examin {
  my %examin = @_;
  # process
}

I want to pass multiple arrays to a subroutine

If you want to pass multiple arrays to a subroutine, you need to pass them as an array reference.

my @array1;
my @array2;

func (\@array1, \@array2);

sub func {
  my ($array1, $array2) = @_;
}

If you pass two arrays as shown below, it will become one array and it will not work.

my @array1;
my @array2;

func (@array1, @array2);

sub func {
  # It becomes one array
  my @array = @_;
}

Pass arrays and hashes separately to subroutine

What if I want to put both an array and a hash in a subroutine? In such cases, you need to use array reference and hash reference.

# Passing side
my $max_num = summary ([1, 2, 3], {how =>'max'});

# Recipient
sub summary {
  my ($nums, $option) = @_;
  # process                            
}

Allow both "hash" and "hash reference" to be received as subroutine arguments

To receive a hash or hash reference in a subroutine, write:

func (name =>'Ken', age => 19);
func ({name =>'Ken', age => 19});

sub func {
  # Convert to hash reference as needed
  my $arg = ref $_[0] eq 'HASH' ? $_[0] : {@_};
}

If the argument is a hash reference, it is assigned as it is, and if it is a hash, it is converted to a hash reference. $_[0] is the first element of the argument @_.

Typical pattern of how to receive arguments

Here is a typical pattern of how to receive arguments.

(1) Multiple scalars

search ('aiueo', 'eo', 2);

sub search {
  my ($str, $search, $offset) = @_;
}

Receive in a list and assign each value in the list to a scalar on the receiving side.

(2) Simple list

average (1,2,3,4,5);

sub average {
  my @nums = @_;
}

Receive it in a list and assign it to an array.

(3) One scalar and list

search_file ('file', 'apple', 'dog');

sub search_file {
  my ($file, @search_list) = @_;
}

The first argument is assigned to the scalar, and the second and subsequent arguments are assigned to the array.

(4) Simple hash

search_arg_hash (str =>'aiueo', search =>'eo', offset => 2);

sub search_arg_hash {
  my %arg = @_;
  my ($str, $search, $offset) = @arg {'str', 'search', 'offset'};
}

Substitute in the hash on the receiving side. If the number of arguments increases, it is a nice interface to give the arguments a name using a hash.

It is not always necessary to reassign the hash to the scalar, but it is often easier to see and code.

(5) One scalar and hash

parse_file ('in_file', out_file =>'out_file', search_path =>'dir');

sub parse_file {
  my ($in_file,%opt) = @_;
  my ($out_file, $search_path) = @opt {'out_file', 'search_path'};
  return;
}

Assign the first argument to the scalar and the second and subsequent arguments to the hash. You can use this interface if the first argument is a required argument and the other arguments are considered optional.

Subroutine return value

Return the scalar value as the return value

Basically, the scalar value is returned as the return value of the subroutine.

sub func {
  my $name = 'Ken';

  return $name;
}

Return an array or hash as a return value

Perl can also return lists (arrays and hashes).

func {
  my @nums = (1, 2, 3);

  return @nums;
}

However, this method is not recommended.The recommended method is to return the "array reference" and "hash reference" described below.

You can also use wantarray function to return arguments depending on the context of the caller, but this is not recommended. The reason is that changing the return value depending on the context forces the user to write "scalar func ()" at some point to enforce the scalar context.

Return reference as return value

Array reference and hash reference are also scalar values, so they can be returned as return values.

# Returns an array reference as a return value
sub func {
  my $nums = [1, 2, 3];

  return $nums;
}

# Returns a hash reference as a return value
sub func {
  my $score = {math => 100, english => 90};

  return $score;
}

Single return

A single return returns an undefined value undef in a scalar context and an empty list () in a list context.

sub func_name {
  # process ...
  return;
}

It is customary to use a "single return" if you want to return an undefined value. "Return undef" has some advantages, but it seems to be used less frequently.

Setting default values

You may want to specify a default value for the subroutine argument. In such a case, if the argument is undefined, set the default value.

sub num {
  my $num = shift;
  unless (defined $num) {
    $num = 0;
  }
}

Since Perl 5.10 introduced a convenient "defined-or operator", you can also write: If the left side is undefined, the value on the right side will be assigned.

sub num {
  my $num = shift;
  $num //= 0;
}

Error handling

Explains how to handle errors in subroutine.

How to return undef

The easiest way is to return "undef" when the subroutine fails. Returns undef with a single return.

sub foo {
  
  my $error;
  
  # ...
  
  if ($error)
    return;
  }
}

The caller checks the return value.

my $ret = foo ();

unless (defined $ret) {
  # Error handling
}

How to throw an exception

The recommended method is to throw an exception when an error occurs. Use the die function to throw an exception.

sub foo {
  
  my $error;
  
  # ...
  
  if ($error)
    die "Error";
  }
}

If you want to throw an exception in a module, use the carp module's croak function. The caller information is easy to understand.

use Carp 'croak';

sub foo {
  
  my $error;
  
  # ...
  
  if ($error)
    croak "Error";
  }
}

The caller catches the exception as follows: You can catch exceptions by using eval. Note that we need a semicolon at the end of the eval block.

eval {
  foo ();
};

if (my $error = $@) {
  # Error handling
}

When an exception occurs, the content of the error is stored in predefined variable called "$@". Since "$@" may be overwritten by a global variable, it is recommended to assign it to a lexical variable immediately.

For a detailed explanation of exception handling, see "Perl's" Exception Handling "Mechanism-Error Notification and Detection".

Subroutine exercises

I have created an exercise to understand the subroutine properly.

Learning themes

CSV, array of arrays, array of hashes, maximum and minimum values, sort, bubble sort, ascending, descending order

Subroutine reference

This is a description of the subroutine reference.

Learning themes

Subroutine reference, polymorphism, dispatch tables, signal handlers, event-driven programming

Subroutine technique

Function parenthesis omission rules

You may or may not use builtin functions parentheses.

# With parentheses
print('Hello');

# Without parentheses
print'Hello';

You may or may not use parentheses for functions imported from the module.

# Functions imported from module
use Carp 'croak';
croak'Error';

Parentheses are required if the function definition is after the position where the function is used.

# Parentheses are required if the function definition is at the end
func ();

sub func {
  ...
}

There is no such criterion as to whether to omit the parentheses. Decide on "whether it is easy for others to read" and "beauty".

* Regarding the relationship with the prototype, I will not write it because the prototype is deprecated.

Redefine subroutine (monkey patch)

Perl allows you to redefine a subroutine definition once it has been done.

sub sum {...}
no warnings'redefine';
sub sum {...}

If you redefine a subroutine, you will be warned of the redefinition. You can remove the warnings by writing no warnings'redefine'; to remove this.

Overwriting a subroutine is sometimes referred to as a monkey patch. If you find a subroutine that has a bug, you can temporarily overwrite the subroutine and apply a patch.

caller function - get the name of the function you are executing

Use the caller function to get the name of the function you are executing. For the caller function, see "caller function - get the name of the function being executed".

Get the arguments of the calling subroutine

You can use the caller function to get the package name, subroutine name, etc. of the caller of the function. It is also possible to get the arguments of the calling subroutine.

To get the arguments of the calling function, call the caller function in the DB namespace in the list context. @DB::args is set to the argument of the calling function. DB is a module used for debugging. Since the namespace will be temporarily changed to DB, let's enclose it in a block. When the block is finished, it will return to the original namespace.

sub a2 {
  {
    # Change to DB package
    package DB;
    
    # When you call the caller function in list context
    my @c = caller 1;
    
    # Arguments are stored in @DB::args
    my @args = @DB::args;
  }
}

Subroutine autoloading

Perl has a feature called autoloading that defines a function that will be executed if a subroutine isn't defined.

Dynamic creation of subroutine

You can dynamically create subroutine in Perl.

Creating a closure

For information on creating "closures" in Perl, see How to create "closures" in Perl.

Reading material about subroutine

List of Perl builtin functions

If you want to see a list of Perl builtin functions, see List of Perl functions.

Related Informatrion