Beefy Boxes and Bandwidth Generously Provided by pair Networks
good chemistry is complicated,
and a little bit messy -LW

comment on

( #3333=superdoc: print w/replies, xml ) Need Help??
A dispatch table is just a mapping from strings to actions. If you find yourself lamenting the lack of a C-style switch/case statement in Perl, and you find yourself grumbling that the equivalent series of if statements is a linear search, you probably want a dispatch table. In Perl, the hash is a natural way to implement this.

There is an implementation in CPAN, but I don't think it's what we're looking for. It's certainly not straightforward, and dispatch tables are easy enough to roll your own.

The trivial case

A basic dispatch table might look like this:
my %disp_table = ( something => \&do_something );
You put a string in, you get a code ref out. Then, presumably, you execute the code ref:
What could be simpler?


That's great if what you're looking for is in the table, but if it's not, you're going to get an error for trying to use an empty string as a subroutine ref, because the hash value came up undef. So you need to have an alternative:
($disp_table{'not there'} || sub {})->();
Now if the hash lookup returns nothing, you fall back on a subroutine that doesn't do anything. Of course, you could use a default that did something if you wanted to.

Fall-through (chaining)

What if you've got a bunch of things that map to the same action? You could duplicate your code for each of them:
one => sub { print "Number!\n" }, two => sub { print "Number!\n" }, three => sub { print "Number!\n" },
which should then raise a red flag that you need to abstract it out into its own subroutine. And if 'one' is supposed to do something before falling through, you can embed that sub call in its custom action:
one => sub { print "The loneliest "; number() }, two => \&number, three => \&number,
By chaining calls this way, you can make things "fall through" to whatever you want them to. They are not limited by what comes next (which is good, because in a hash, what comes next is unpredictable).

Matching patterns and ranges

Up until a few minutes ago, I would have said that using a dispatch table precludes pattern matching. I would have been wrong. Super Search on dispatch table came up with an ingenious post by grinder that shows how to do just that, using Regexp::Assemble. In a sense, the pattern match is still searching all the alternatives, albeit in an optimized way. However, the circumstances in which a dispatch table is most advantageous — where you have a very large number of alternatives — are where a regex is likely to bog down.

Ranges offer a similar challenge. Of course, neither patterns nor ranges are handled by C's switch statement. Modula handles ranges, but it sacrifices fall-through (and may only work on numbers and single characters). You can't have everything. If you can't enumerate all the cases you want to cover, you don't want a dispatch table. Functions that check all the alternatives in order (such as my smatch) can offer a great deal of flexibility.

Having Perl build the table

The only really tricky bit about having a subroutine that translates a list of arguments resembling a C switch statement into a dispatch table is in implementing fall-through. A program doesn't have the luxury of creating new named subroutines, so there's a bit of bookkeeping to handle there.

I have implemented a function that does the translation for all the features described above (except patterns and ranges, for the reasons cited) in the Snippet Switch/case as a dispatch table with C-style fall-through.

Update: I have written a module, Case, that implements dispatch tables (as well as a more complex smart-matching construct).

In reply to Implementing Dispatch Tables by Roy Johnson

Use:  <p> text here (a paragraph) </p>
and:  <code> code here </code>
to format your post; it's "PerlMonks-approved HTML":

  • Posts are HTML formatted. Put <p> </p> tags around your paragraphs. Put <code> </code> tags around your code and data!
  • Titles consisting of a single word are discouraged, and in most cases are disallowed outright.
  • Read Where should I post X? if you're not absolutely sure you're posting in the right place.
  • Please read these before you post! —
  • Posts may use any of the Perl Monks Approved HTML tags:
    a, abbr, b, big, blockquote, br, caption, center, col, colgroup, dd, del, div, dl, dt, em, font, h1, h2, h3, h4, h5, h6, hr, i, ins, li, ol, p, pre, readmore, small, span, spoiler, strike, strong, sub, sup, table, tbody, td, tfoot, th, thead, tr, tt, u, ul, wbr
  • You may need to use entities for some characters, as follows. (Exception: Within code tags, you can put the characters literally.)
            For:     Use:
    & &amp;
    < &lt;
    > &gt;
    [ &#91;
    ] &#93;
  • Link using PerlMonks shortcuts! What shortcuts can I use for linking?
  • See Writeup Formatting Tips and other pages linked from there for more info.
  • Log In?

    What's my password?
    Create A New User
    and the web crawler heard nothing...

    How do I use this? | Other CB clients
    Other Users?
    Others having an uproarious good time at the Monastery: (4)
    As of 2021-03-01 07:55 GMT
    Find Nodes?
      Voting Booth?

      No recent polls found