I'm trying to implement a dispatch table which calls functions inside a Perl module. I know how to implement dispatch tables generally, but I can't seem to get it right when referencing an object method from within $self. Maybe I haven't Googled enough, but so far, the right syntax is elusive.
I have traced the parameters though the calls, and I know what is happening -- the function references are not receiving a reference to $self as their first parameter. This is what I currently have inside $self. I believe I copied this over properly; if I made a mistake and it doesn't run, I apologize.
package MyRefHashTest;
use strict;
use warnings;
sub new {
my $class = shift;
my $self = {
DISPATCH => {
ONE => \&funcOne,
TWO => \&funcTwo,
THREE => \&funcThree,
FOUR => \&funcFour
}
};
bless $self, $class;
return $self;
}
sub funcOne {
my ($self, $param) = @_;
print "func1 $param \n";
}
sub funcTwo {
my ($self, $param) = @_;
print "func2 $param \n";
}
sub funcThree {
my ($self, $param) = @_;
print "func3 $param \n";
}
sub funcFour {
my ($self, $param) = @_;
print "func4 $param \n";
}
sub runTesting {
my ($self, $type) = @_;
($self->{DISPATCH}{$type} || sub {})->("string");
}
1;
# To Test:
$test = MyRefHashTest->new;
$test->runTesting("ONE");
$test->runTesting("TWO");
$test->runTesting("THREE");
$test->runTesting("FOUR");
The actual output I get is that $param is undefined in the function calls from the dispatch table, when it should not be. This is how I know that the references to $self are not where they should be. The functions think that $type is $self.
I have tried editing the hash table references so they look like \$self->functionName, but that only results in a compilation error for $self not being properly defined on that line.
Can anyone guide me to the right syntax for this, please?
Thanks!
EDIT: After much more work, I finally found a solution. It's some very interesting syntax, a lot more complicated than I thought. Essentially, I'm building the hash from the inside out:
my $self = {
DISPATCH => undef
};
$self->{DISPATCH} = {
ONE => sub { $self->funcOne(@_); },
TWO => sub { $self->funcTwo(@_); },
THREE => sub { $self->funcThree(@_); },
FOUR => sub { $self->funcFour(@_); }
};
It works, but it seems like a lot of hassle for what it is. If anyone knows of an easier way to do this, I would still be very interested in it. If there isn't an easier way, on the other hand, I hope this can help somebody.
What follows are four approaches for implementing a method-based dispatch table. The differences explained afterwards.
my %DISPATCH = (
ONE => \&funcOne,
TWO => \&funcTwo,
THREE => \&funcThree,
FOUR => \&funcFour,
);
sub runTesting {
my ($self, $type) = @_;
my $method = $DISPATCH{$type};
return $self->$method("string");
}
or
my %DISPATCH = (
ONE => __PACKAGE__->can('funcOne'),
TWO => __PACKAGE__->can('funcTwo'),
THREE => __PACKAGE__->can('funcThree'),
FOUR => __PACKAGE__->can('funcFour'),
);
sub runTesting {
my ($self, $type) = @_;
my $method = $DISPATCH{$type};
return $self->$method("string");
}
or
my %DISPATCH = (
ONE => 'funcOne',
TWO => 'funcTwo',
THREE => 'funcThree',
FOUR => 'funcFour',
);
sub runTesting {
my ($self, $type) = @_;
my $method_name = $DISPATCH{$type};
return $self->$method_name("string");
}
or
my %DISPATCH = (
ONE => sub { shift->funcOne(@_) },
TWO => sub { shift->funcTwo(@_) },
THREE => sub { shift->funcThree(@_) },
FOUR => sub { shift->funcFour(@_) },
);
sub runTesting {
my ($self, $type) = @_;
my $cb = $DISPATCH{$type};
return $cb->($self, "string");
}
All four approaches allow the methods to be defined in the same class.
The last three approaches allow the methods to be defined in a superclass as well.
The last two approaches allow a subclass to provide or override the method as well. These are your best options.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With