Reputation: 95
I found that the fastest way to dispatch many functions in perl is to use function references. The remaining problem is, that I have to include the function names in an our ($func1, $func2, ...) list both in the dispatcher and in the function module. I could not fin d any way to include them, like C include would do. Here my code: Main module:
use strict;
our ($base);
$base = '/home/en/dtest/perl/forditas/utf8/forditas/test1';
require("$base/disph1.pl");
require("$base/fut1h1.pl");
for (my $j = 0; $j < 5; $j++){
dispatch($j);
}
Dispatcher module:
use strict;
our ($base);
require("$base/fut1h1.pl");
our ($sref1, $sref2, $sref3, $sref4, $sref5); # This is what I'd like to include
my %shash = (
'0' => $sref1,
'1' => $sref2,
'2' => $sref3,
'3' => $sref4,
'4' => $sref5,
);
sub dispatch($){
my ($ix) = @_;
my ($a, $b, $c);
$a = 1; $b = 2; $c = 3;
my $ref = $shash{$ix};
&$ref($a,$b, $c);
}
1;
Function module:
use strict;
our ($sref1, $sref2, $sref3, $sref4, $sref5); # This is what I'd like to include
$sref1 = sub($$$) {
my ($a,$b,$c) = @_;
print "sub1 $a,$b,$c\n";
};
$sref2 = sub($$$) { my ($a,$b,$c) = @_; print "sub2 $a, $b, $c\n"; };
$sref3 = sub { print "sub3\n"; };
$sref4 = sub { print "sub4\n"; };
$sref5 = sub { print "sub5\n"; };
1;
This is the result of a run:
$ perl enhufh1.pl
sub1 1,2,3
sub2 1, 2, 3
sub3
sub4
sub5
Thanks in advance for tips.
Upvotes: 0
Views: 329
Reputation: 29844
First of all mapping integers to elements is a misuse of hash. You might as well use arrays.
Then second, you seem to want to isolate algorithm from implementation, joining them in a main script. While this is admirable, it's clear that the functions module knows something of what it is being used for. Thus while deriving a sort of knowledge graph, the simplest case is that your function module knows the diapatch module.
You can just create a helper function for this purpose:
use strict;
use warnings;
our @EXPORT_OK = qw<setup_dispatch dispatch>;
use parent 'Exporter';
my @dispatch_subs;
sub setup_dispatch { @dispatch_subs = @_; }
sub dispatch {
my ($a, $b, $c) = ( 1, 2, 3 );
return $dispatch_subs[shift()]->( $a, $b, $c );
}
Now your function module can call the setup funciton:
use strict;
use warnings;
use Dispatch ();
Dispatch::setup_dispatch(
# I echo the caution about using prototypes
sub ($$$) {
my ($a,$b,$c) = @_;
print "sub1 $a,$b,$c\n";
}
, sub ($$$) { my ($a,$b,$c) = @_; print "sub2 $a, $b, $c\n"; }
, sub { print "sub3\n"; }
, sub { print "sub4\n"; }
, sub { print "sub5\n"; }
);
And you would just use both of them in the main module like this:
use strict;
use warnings;
require 'plugin_functions.pl';
use Dispatch qw<dispatch>;
...
You really don't need "names" if you just want to use "indexed" generic names. Just put them in a list.
Upvotes: 1
Reputation: 126722
You really should be using Perl modules - *.pm
files - and including them where they are needed with use
. Making these modules subclasses of Exporter
allows them to export variable and aubroutine names into the calling package.
Take a look at this set of three sources, which also add several improvements on your original code.
Note that you can use the @EXPORT
array instead of @EXPORT_OK
, in which case the corresponding use
statement doesn't have to list the symbols to be imported. However it is better to have the symbols listed at the point of use, otherwise the code for the module has to be inspected to discover exactly what is being imported.
main.pl
use strict;
use warnings;
use lib '/home/en/dtest/perl/forditas/utf8/forditas/test1';
use Dispatcher qw/ dispatch /;
dispatch($_) for 0 .. 4;
/home/en/dtest/perl/forditas/utf8/forditas/test1/Dispatcher.pm
package Dispatcher;
use strict;
use warnings;
require Exporter;
our @ISA = qw/ Exporter /;
our @EXPORT_OK = qw/ dispatch /;
use Utils qw/ sub1 sub2 sub3 sub4 sub5 /;
my @dtable = ( \&sub1, \&sub2, \&sub3, \&sub4, \&sub5 );
sub dispatch {
my ($i) = @_;
my ($a, $b, $c) = (1, 2, 3);
$dtable[$i]($a, $b, $c);
}
1;
/home/en/dtest/perl/forditas/utf8/forditas/test1/Utils.pm
package Utils;
use strict;
use warnings;
require Exporter;
our @ISA = qw/ Exporter /;
our @EXPORT_OK = qw/ sub1 sub2 sub3 sub4 sub5 /;
sub sub1 {
my ($a, $b, $c) = @_;
print "sub1 $a,$b,$c\n";
}
sub sub2 {
my ($a, $b, $c) = @_;
print "sub2 $a, $b, $c\n";
}
sub sub3 {
print "sub3\n";
}
sub sub4 {
print "sub4\n";
}
sub sub5 {
print "sub5\n";
}
1;
output
sub1 1,2,3
sub2 1, 2, 3
sub3
sub4
sub5
Upvotes: 1
Reputation:
What you need is Exporter
.
Within your module:
require Exporter;
@EXPORT = qw($sref1 $sref2 $sref3);
However, it might be worth considering a different design:
Script:
set_dispatch(0,sub{ .... });
Dispatcher Module:
my @dispatch; #If just indexing to numbers, use an array instead of a hash.
sub set_dispatch {
$dispatch[$_[0]] = $_[1];
}
Main module:
for (0..4) #equivalent to before, but more Perlish.
{
dispatch($_);
}
Using a function call to set up the dispatch functions is better than exporting a bunch of variables, to my mind.
Upvotes: 0