eleonora
eleonora

Reputation: 95

dispatch functions in perl, how to include our list

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

Answers (3)

Axeman
Axeman

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

Borodin
Borodin

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

user1919238
user1919238

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

Related Questions