I have a dispatch table that I wish to initialize only once, and is only intended to be used by one function. I was hoping to move the dispatch table outside of the subroutine and into the same anonymous block, but since the dispatch table uses closures to call methods for the object passed into the function, moving the table outside the function separates it from access to the object. What other options do I have for this dispatch table?
I'm using Perl 5.8, so unfortunately I'm unable to use state
variables.
sub foo {
my ($self, $var) = @_;
my %funcs = (
a => sub { $self->_a() },
b => sub { $self->_b() },
...
);
return $funcs{$var}->();
}
Your functions in the dispatch table are closures over $self
. If you pass in the $self
as a parameter, you can get around that. Note that state
variables are not true closures over $self
, and would require an explicit parameter as well.
my %funcs = (
a => sub { shift->_a }, # these are like anonymous methods
b => sub { shift->_b },
);
sub foo {
my ($self, $var) = @_;
my $meth = $funcs{$var} || die "There is no entry $var";
return $self->$meth(); # sugary syntax
}
Here is a demonstration why state
would be a bad idea:
use 5.010;
package Foo;
sub new { my ($c, $v) = @_; bless \$v, $c }
sub foo {
my ($self) = @_;
state $cb = sub { say $$self };
$cb->();
}
Foo->new($_)->foo for 1..3;
Output:
1
1
1
The inner sub is a closure, but the initialization of $cb
is only performed once. Thus the closed over $self
is the first one.
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