Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Implementing a dispatch table

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.

like image 719
Jessica Castrogiovanni Avatar asked Mar 04 '23 12:03

Jessica Castrogiovanni


1 Answers

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.

like image 152
ikegami Avatar answered Mar 15 '23 23:03

ikegami