My task was to write a file processor that would perform some data manipulation in different file types. Since the general mechanism was the same for all files, but the procedure differed slightly for each file type I decided to build one function that would serve as a framework and little specialized functions to handle operations for each file type. That sounded reasonable and would provide elegant solution, preventing code duplication at the same time. The only problem was how.
Since passing function pointers is possible in C, why shouldn’t it be in Perl, I asked? While my Perl skills are rather rusty (last time I used it was a few years ago) I was still able to come up with the solution after browsing Perl documentation and googling a bit. I couldn’t find a clear example of handling function references, though, and that’s why I’m writing this now.
Two simple functions for different file types, they will be passed by reference later:
# type1 requires second token in each line to be
# turned to upper case
sub type1_handler {
my $line = shift;
# ignore comments
if ($line !~ m/^#/) {
my @parts = split(/ /, $line);
# capitalize second token in line
$parts[1] = uc $parts[1];
$line = join(” “, @parts);
}
return $line;
}
# type2 requires second token in each line to be
# turned to lower case
sub type2_handler {
my $line = shift;
# ignore comments
if ($line !~ m/^#/) {
my @parts = split(/ /, $line);
# capitalize second token in line
$parts[1] = lc $parts[1];
$line = join(” “, @parts);
}
return $line;
}
General file handling function, it takes two parameters: reference to the line handling function and list of file names to be processed. It uses get_file_name() function (not defined here) to generate new file name for the output file. Here’s the code:
my $OUTPUT_DIR = './output/';
sub process_files {
my ($line_handler, @files) = @_;
foreach my $file_name (@files) {
print "Processing: $file_name \n";
my $new_file_name = get_file_name($file_name);
open(INPUT, " $OUTPUT_DIR$new_file_name") or die("Could not open output file: $OUTPUT_DIR$new_file_name \n");
while (my $line = <INPUT>) {
print OUTPUT &$line_handler($line);
}
close(INPUT) or die("Could not close input file: $file_name \n");
close(OUTPUT) or die("Could not close output file: $OUTPUT_DIR$new_file_name \n");
}
}
As you can see, function reference can be stored in a scalar variable. Once you want to call referenced function, you use ampersand (&) before the reference name, like this: &$reference_name($param1, $param2)
How to create function references and pass them to other functions? You simply need to put a backslash and ampersand (\&) in front of the function name. Example:
#process type1 files
process_files(\&type1_handler, <*.type1>);
# process type2 files
process_files(\&type2_handler, <*.type2>);
As you can see, using function references in Perl is pretty simple, once you find out how to pass them around.