Anonymous Subroutines and Subroutine References - Page 3
June 25, 2001
Less common than named subroutines, but just as valid, are
anonymous subroutines. As their name suggests, anonymous
subroutines do not have a name. Instead they are used as
expressions, which return a code reference to the subroutine
definition. We can store the reference in a scalar variable (or
as an element of a list or a hash value) and then refer to it
through the scalar:
my $subref = sub {print "Hello anonymous subroutine";};
In order to call this subroutine we use the ampersand prefix.
This instructs Perl to call the subroutine whose reference this
is, and return the result of the call:
# call an anonymous subroutine
&$subref;
&$subref ("a parameter");
This is one of the few places that an ampersand is still used. However, even here it is not required; we
can also say:
$subref->();
$subref->("a parameter");
These two variants are nearly, but not quite, identical. Firstly,
&$subref; passes the current @_ array (if any) directly into
the called subroutine, as we briefly mentioned earlier. Secondly,
the ampersand disables any prototypes we might have defined for
the subroutine. The second pair of calls retains the prototype in
place. (We cover both of these points later in the chapter.)
We can generate a subroutine reference from a named subroutine
using the backslash operator:
my $subref = \&mysubroutine;
This is more useful than one might think, because we can pass a
subroutine reference into another subroutine as a parameter. The
following simple example demonstrates a subroutine taking a
subroutine reference and a list of values, and returning a new
list generated from calling the subroutine on each value of the
passed list in turn:
#!/usr/bin/perl
# callsub.pl
use warnings;
use strict;
sub do_list {
my ($subref, @in) = @_;
my @out;
map {push @out, &$subref ($_)} @in;
return @out;
}
sub add_one {
return $_[0] + 1;
}
$, = ",";
print do_list (\&add_one, 1, 2, 3); # prints 2, 3, 4
Some Perl functions (notably sort), also accept an anonymous
subroutine reference as an argument. We do not supply an
ampersand in this case because sort wants the code reference, not
the result of calling it. Here is a sort program that
demonstrates the different ways we can supply sort with a
subroutine. The anonymous subroutine appearing last will not work
with Perl 5.005:
#!/usr/bin/perl
# sortsub.pl
use warnings;
use strict;
# a list to sort
my @list = (3, 4, 2, 5, 6, 9, 1);
# directly with a block
print sort {$a cmp $b} @list;
# with a named subroutine
sub sortsub {
return $a cmp $b;
}
print sort sortsub @list;
# with an anonymous subroutine
my $sortsubref = sub {return $a cmp $b;};
print sort $sortsubref @list;
Of course, since we can get a code reference for an existing
subroutine we could also have said:
$sortsubref = \&sortsub;
The advantage of using the anonymous subroutine is that we can
change the subroutine that sort uses elsewhere in the program,
for example:
# define anonymous subroutines for different sort types:
$numericsort = sub {$a <=> $b};
$stringsort = sub {$a cmp $b };
$reversenumericsort = sub {$b <=> $a};
# now select a sort method
$sortsubref = $numericsort;
The disadvantage of this technique is that unless we take care to
write and express our code clearly, it can be very confusing to
work out what is going on, since without running the code it may
not always be possible to tell which subroutine is being executed
where. We can use print $subref to print out the address of the
anonymous subroutine, but this is not nearly as nice to read as a
subroutine name.
It is also possible to turn an anonymous subroutine into a named
one, by assigning it to a typeglob. This works by manipulating
the symbol table to invent a named code reference that Perl
thereafter sees as a subroutine definition. This leads to the
possibility of determining the actual code supported by a
subroutine name at run time, which is handy for implementing
things like state machines. This will be covered more fully in
'Manipulating the Symbol Table Directly' in Chapter 8.
Subroutines - Page 2
Professional Perl Programming
Strict Subroutines and the 'use strict subs' Pragma - Page 4
|