Did you get much variation in the working results? It seems kind of straightforward to me, but maybe it's because I'm too used to that idiom.
Is a hash the recommended way to implement a dispatch table in Perl?
There are at least two ways to do this with an array (either the key is an enum, or you iterate over the array for each call), but I wanted to try with closures (with an OO interface, to hide the complexity of creating the closure chain when adding the callbacks):
use strict;
use warnings;
# Callback functions ---------------------------------------
sub first_callback {
my $z = shift;
print "in first_callback, z=$z\n";
return 1;
}
sub last_callback {
my $z = shift;
print "in last_callback, z=$z\n";
return 2;
}
# Implementation of dispatch table -------------------------
# (You need to write this code)
package Invoker
{
sub new
{
my ($class, $default) = @_;
bless \(sub { shift; $default->(@_) }), $class;
}
sub add
{
my ($self, $key, $callback) = @_;
my $alt = $$self;
$$self = sub { my $name = shift; $name eq $key ? $callback->(@_) :
+ $alt->($name => @_) };
$self;
}
sub dispatch
{
my $self = shift;
&{ $$self }(@_);
}
}
sub default_callback
{
return -1;
}
my $invoker = Invoker->new(\&default_callback)
->add(first => \&first_callback)
->add(last => \&last_callback);
sub invoker {$invoker->dispatch(@_)};
# Main program for testing ---------------------------------
for my $name ( "first", "last", "fred" ) {
my $rc = invoker( $name, $name . '-arg' );
print "$name: rc=$rc\n";
}
This creates a chain of closures that each contain a key, the corresponding callback and a ref to the next closure in the chain. If the name matches the key, the callback is called, otherwise the parameters are passed to the next closure in the chain.
At first this was just supposed to be a silly implementation, though it did make me think about your first question: a hash is the best solution when using an exact match to a key as the dispatch condition, but the (iterative) array-based or closure-based implementations can accept any condition (though the only advantage of the closure-based solution over array-based is that it's more fun).
Edit: the init method has been renamed new, because I don't know why I didn't just do that in the first place. And made the explanation more complete
-
Are you posting in the right place? Check out Where do I post X? to know for sure.
-
Posts may use any of the Perl Monks Approved HTML tags. Currently these include the following:
<code> <a> <b> <big>
<blockquote> <br /> <dd>
<dl> <dt> <em> <font>
<h1> <h2> <h3> <h4>
<h5> <h6> <hr /> <i>
<li> <nbsp> <ol> <p>
<small> <strike> <strong>
<sub> <sup> <table>
<td> <th> <tr> <tt>
<u> <ul>
-
Snippets of code should be wrapped in
<code> tags not
<pre> tags. In fact, <pre>
tags should generally be avoided. If they must
be used, extreme care should be
taken to ensure that their contents do not
have long lines (<70 chars), in order to prevent
horizontal scrolling (and possible janitor
intervention).
-
Want more info? How to link
or How to display code and escape characters
are good places to start.