in reply to When should I use a dispatch table?
I think performance optimization should not be the principle determining factor in deciding which technique to use. Unless your application is running unacceptably slowly and you've identified the multi-branch if/else section as a bottleneck, it's ridiculous to change that to something else just for a performance gain.
Maintainability, and design — as in consistency of — those are of primary importance.
I like dispatch tables. They're clever. But at the same time, they raise a red flag for me — the same one I see whenever hashes are used to store a static set of entities in an application: It completely undermines the safety of strict. (There are steps you can take to regain some of this safety, such as using Tie::StrictHash.)
The solution is to make the subs named class methods. I recently did this on a project at work.
I had two dispatch tables, one for the "real" functions and one for a set of stubs, to be used when debugging.
Old way:
my %real_functions = ( wipe_system => sub { system "rm -rf /" }, ); my %debug_stubs = ( wipe_system => sub { warn "wiping system (no, not really)\n" }, ); my $funcs = $debug ? \%debug_stubs : \%real_functions; $funcs->{'wipe_system'}->();
New way:
{ package SystemFunctions::Real; sub wipe_system { shift; # will be the class name system "rm -rf"; } } { package SystemFunctions::Debug; sub wipe_system { shift; # will be the class name warn "wiping system (no, not really)\n"; } } my $funcs = $debug ? 'SystemFunctions::Real' : 'SystemFunctions::Debug'; $funcs->wipe_system();
Now, it sometimes won't be convenient to do this, due to the complication of packages. In my case, it was; in fact, it was a significant improvement, since it gave me a convenient place to encapsulate all my "system functions", which hitherto had lived in the main namespace.
In the very simplest cases, you don't need to worry about packages at all:
becomesmy %dispatch = ( incr => sub { $x++ }, decr => sub { $x-- }, ); $dispatch{$op}->();
sub incr { shift; $x++ } sub decr { shift; $x-- } main->$op();
Note: I only left the shift in as a reminder that it will always be necessary unless the sub takes no arguments (or, as I sometimes do, you pop the args rather than shifting them).
Finally, what about default cases? One possibility is to use AUTOLOAD.