Beefy Boxes and Bandwidth Generously Provided by pair Networks
go ahead... be a heretic
 
PerlMonks  

Re: Rosetta Dispatch Table

by Eily (Monsignor)
on Nov 22, 2017 at 17:45 UTC ( [id://1204051]=note: print w/replies, xml ) Need Help??


in reply to Rosetta Dispatch Table (Interview Question)

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

Replies are listed 'Best First'.
Re^2: Rosetta Dispatch Table
by Eily (Monsignor) on Nov 22, 2017 at 18:31 UTC

    Bonus (got the idea by reading tybalt89's version)

    sub Invoker::first { shift; &first_callback } sub Invoker::last { shift; &last_callback } sub Invoker::AUTOLOAD { -1 } sub invoker { my $name = shift; Invoker->$name(@_); }
    It looks and kind of quacks like a symbolic ref on the method name, except it works under strict and warnings.

    Edit: Actually if you ignore the first parameter of the callbacks, you can just use the symbols table as the containing hash and use the method above :)

    use strict; use warnings; # Callback functions --------------------------------------- sub first_callback { my (undef, $z) = @_; print "in first_callback, z=$z\n"; return 1; } sub last_callback { my (undef, $z) = @_; print "in last_callback, z=$z\n"; return 2; } sub default_callback { -1 } # Dispatch ------------------------------------------------- %Dispatch:: = ( first => *first_callback, start => *first_callback, last => *last_callback, AUTOLOAD => *default_callback); sub invoker { my $name = shift; Dispatch->$name(@_); } # Main program for testing --------------------------------- for my $name ( qw< first start last fred > ) { my $rc = invoker( $name, $name . '-arg' ); print "$name: rc=$rc\n"; }

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: note [id://1204051]
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others wandering the Monastery: (5)
As of 2024-04-23 11:35 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found