
Using Dispatch Tables to Avoid Conditionals in JavaScript - shawndumas
http://designpepper.com/blog/drips/using-dispatch-tables-to-avoid-conditionals-in-javascript
======
SoapSeller
You can further improve dispatch tables in js by using bind.

so something like:

    
    
      north: function() { movePlayer("north"); },
    

becomes:

    
    
      north: movePlayer.bind(this, "north"),
    

or using underscore.js(for greater browser compatibility):

    
    
        north: _.bind(movePlayer, this, "north"),

~~~
taf2
or instead of a whole library use mozilla's compatibility when using bind...
see the function here: [https://developer.mozilla.org/en-
US/docs/JavaScript/Referenc...](https://developer.mozilla.org/en-
US/docs/JavaScript/Reference/Global_Objects/Function/bind)

~~~
k3n
Because modifying object prototypes is the way to go?

~~~
taf2
Depends if you're in an environment you control then yes - when embedding your
scripts, don't do it. Create your own isolated functions and assume anything
and everything can be broken e.g. Array.prototype is often modified with
broken or semi incomplete functions like broken versions of indexOf

------
MatthewPhillips
While this can be a useful construct when you are doing meta-programming, this
particular example is horrible. It's not much more readable (would be less
readable in an 80x24 terminal window), and now you have an extra object
sitting in memory for the lifetime of your application. If you only have a
handful of options, just use switch.

~~~
mistercow
>and now you have an extra object sitting in memory for the lifetime of your
application

Worrying about that would be the epitome of premature optimization.

------
chime
I use something similar when rendering form fields dynamically.

    
    
        draw_checkbox = function() {}
        draw_radio    = function() {}
        draw_select   = function() {}
    
        draw_field = function(type) {
          this['draw_' + type]();
        }
    
        draw_list = function(list) {
           for(i = 0; i < list.length; i++)
             draw_field(list[i].type);
        }
    

For sake of simplicity, I did not include the code to verify that type is
proper and parameters sent to each function.

~~~
nahname
This is probably the part I dislike most about ruby (I know this is JS). There
are some places where this trick makes a painful piece of code go away, so I
appreciate why it was selected. The problem is that you now have no reference
to draw_checkbox being used in your entire code base and when someone else is
refactoring, they think they can remove it.

Personally, I would never elect to go this route because it only introduces
overhead for refactoring and code maintenance. I would rather see a mess of
procedural code, than some silly clever little tricks that will trip up all
the new people.

~~~
taf2
yeah, i kinda agree.. in this case I'd have done something more like:

    
    
       function Renderer() {}
       Renderer.prototype = {
         draw: {
            checkbox: function() {},
            radio: function() {},
            select: function() {},
            field: function(type) {
              this[type]();
            },
            list: function(items) {
              return items.map(function(item) {
                return this.field(item.type)
            });
           }
        }
       }

Perhaps I'm just comment trolling though - totally depends on how the code
would have been used...

~~~
chime
Actually my code ends up looking pretty much like yours. I use CoffeeScript
and was writing a simplified JS equivalent off the top of my head since this
post was about JS. Similar to your Renderer, I have a DrawForm class that
iterates through DrawField class objects which provide the checkbox(), radio()
etc. methods.

My point was that in the end, you get to do dynamic function instantiation,
which is pretty awesome in JS.

------
arianvanp
I've done this before in scenarios of packet handling. e.g.

    
    
        packets.incoming[16] = {
            login_size:     {type: 'byte'},
            magic_code:     {type: 'byte'},
            client_version: {type: 'short'},
            high_detail:    {type: 'byte'},
            archive_crc:    {type: ['int', 9]},
            reported_size:  {type: 'byte'},
            block_opcode:   {type: 'byte'},
            client_key:     {type: ['int', 2]},
            server_key:     {type: ['int', 2]},
            uid:            {type: 'int'},
            username:       {type: 'string'},
            password:       {type: 'string'}
        };
    
        packets.outgoing[253] = packets.outgoingMessage  = function (message) {
            var length = message.length + 1;
                return {
                    opcode:    {type:'byte',          value: 253},
    		length:     {type:'byte',           value: length},
    		message:	{type:'string',        value: message}
                };
        };

------
Xcelerate
"Dispatch table"? I'm surprised everything in programming has a name
associated with it. I just called these Javascript objects representing a map
of functions...

~~~
k3n
lol yeah, in some languages they even call that a _class_!

~~~
joezydeco
30 years ago we called this a _vector table_ on a microprocessor. What's old
is new again...

~~~
k3n
I don't know about you, but I'm digging these thinclient+mainframe [cloud-
based] apps.

~~~
joezydeco
Agree. But I think there's a great future in PC (Personal Cloud) systems. Lots
of potential there.

------
mgrouchy
Interesting. Ive seen something similar to this quite often used in Python
because it doesn't have Switch statements.

~~~
gvalkov
Indeed, it's quite idiomatic. I would have still preferred if there was a
switch/case construct that would generate a dispatch table for us (in fact,
this was proposed and rejected in pep 3103[1]). A case statement would have
been a nice, little addition to the expressiveness of Python, but it's not
that big of a deal.

Here's another dispatch table technique that I really like[2].

[1]: www.python.org/dev/peps/pep-3103/

[2]: [http://code.activestate.com/recipes/577864-fast-and-
elegant-...](http://code.activestate.com/recipes/577864-fast-and-elegant-
switchcase-like-dispatch/)

------
obeattie
Is it just me, or for this example does the "dispatch table" seem way more
complex (and likely less efficient) than the switch statement? The original is
not difficult at all to interpret.

~~~
nahname
The dispatch table is shorter than the switch, so there is a lot less noise.
The invocation is a little clever, but overall I would consider them about
equally complex. Maybe you meant unconventional?

The performance is substantially different. The dispatch table is ~75% slower
(in chrome). <http://jsperf.com/switchvsdispatchtable>

One thing I really like about dispatch tables is that it forces the developer
to only be able to handle the decision logic. The number of times I've had to
cleanup a switch with 20-30 lines under each condition (sometimes including
another switch) is too many to count.

~~~
drgath
> The performance is substantially different. The dispatch table is ~75%
> slower (in chrome).

Of course those are, they're doing very different things in that test case.
Your first case is just returning a value, and the second is executing a
function to return a value. Here's a better comparison,
<http://jsperf.com/switchvsdispatchtable/2>

There's nothing inherently slow about dispatch tables, it all about how you
implement them. As someone else mentioned, the OP should be using bind to
reduce the # of function calls instead of executing a function which executes
a function.

------
davidkellis
I think the real win with a technique like this is that, if you store the
bindings in a place that is globally accessible, it is open to extension.

For example, if a JSON library author implemented an encode(object) function
using a dispatch table holding a set of object-type/JSON-encoding-function
pairs, a client could extend the encode function by registering additional
object-type/JSON-encoding-function pairs in the dispatch table.

Edit:

Furthermore, I believe this is how clojure protocols work - when a new type
participates in a protocol, the type-specific function implementation gets
added to a dispatch table keyed on the datatype's java Class. Then, anytime
you invoke the function, the class of the first argument is identified and the
corresponding type-specific function is pulled out of the dispatch table based
on the class.

------
jcampbell1
You have to be careful when doing this type of stuff. For instance, the switch
case is actually doing both validation and switching, where as the dispatch
table does no validation.

Consider: processUserInput('toString');

That has very different behavior in the two different styles.

------
Leszek
I don't know, in this case, with a bit of reformatting the switch can look
pretty similar:

    
    
        function processUserInput(command) {
            switch (command) {
                case "north":    movePlayer("north"); break;
                case "east":     movePlayer("east");  break;
                case "south":    movePlayer("south"); break;
                case "west":     movePlayer("west");  break;
                case "look":     describeLocation();  break;
                case "backpack": showBackpack();      break;
            }
        }
    

Although that's to be expected, a switch on a string value isn't that much
different to a string lookup in an associative array.

~~~
Tactic
Except with an array you can change things programmatically on the fly. Or
have it setup in a configuration file or database table. Very useful.

------
robmcm
The switch statement offers the ability to provide a default opperation, such
as tell the user the command was not found.

You could add an undefined property check on the dispatch table, but then you
have as much and more complex code IMO.

------
ldh
I think the article does a poor job of describing why the dispatch table
version is better, or why you'd want to avoid conditions in the first place.

------
vivin
I've done something similar in my form-validation library. I have a function
that has three inputs that basically end up behaving like flags. So there are
8 possibilities in total. I ended up creating a function that would return a
three-bit binary number based on the inputs, and I also created a jump-table
that maps the three-bit binary values to specific handlers.

------
avolcano
Hey, I used a modified version of this pattern without knowing what it was
called a few months ago: [https://github.com/thomasboyt/Noted-
App/blob/master/app/asse...](https://github.com/thomasboyt/Noted-
App/blob/master/app/assets/javascripts/views/note_view.js#L52)

Really useful when you have lots of keybindings.

------
johnnymonster
This example is great to point out that javascript is a dynamic language and
should be used as such whenever possible. obviously he only used a handful of
options and maybe a switch would work better for this exact example, but it
should get the reader thinking about where else this type of pattern could be
used.

------
binarymax
For more complicated scenarios (where you find yourself making trees of
conditionals), I suggest reading up on finite state machines, and for js
checkout machina:

<https://github.com/ifandelse/machina.js>

------
recuter
This is an excellent tip and makes one wonder why it isn't more commonly seen
in the wild.

~~~
seanalltogether
I'm guessing its just not a common thing to have a large definition of single
line if statements, I'm not sure about other programmers but I don't think I
could find much of this in my code.

------
serbrech
I don't see the benefit. it really is just a disguised switch statement,
unless you do something more dynamic with the mapping between the command name
and the function to call...

