The hashtable closure pattern

I noticed that I was using a pattern of my own more and more. It is actually very usefull, for several reasons. It may have been used by other before me, but never saw a name for it.

This pattern is useful when you have to apply an operation dependent on parameters several times. for example when you want to apply a calculation on all elements of an array, the calculation depending on some parameters. This article will explain you that pattern and demonstrate how it can be used in Javascript, PHP and D.

This pattern can be used in any language that support first class function and hashtable, that is becoming more and more common (closure support was added in PHP as of version 5.3).

An explanation of the pattern and when it can be used

As an example is often more clear than a lot of theoretical chit chat, let’s talk about a concrete case. You want to create a function that present a set of data in different format (pie chart, histograms, etc . . .). We will use Javascript in the first place.

1
2
3
4
5
6
7
8
9
10
11
12
function create_chart(type, datas) {
    for(var i = 0; i < datas.length; i++) {
        switch(type) {
            case 'pie' :
                // Draw the data in a way.
                break;
            case 'histogram' :
                // Draw data another way.
                break;
        }
    }
}

Ok the point was not to show how we can draw a chart, but show what is the structure of the code. This code have a problem : the switch is performed for every data in the chart. This is obvious that the result of the switch is always the same and that it doesn’t belong into the loop. You don’t want calculation to be made for nothing. So let’s put that test outside the loop :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
function create_chart(type, datas) {
    switch(type) {
        case 'pie' :
            for(var i = 0; i < datas.length; i++) {
                 // Draw the data in a way.
            }
            break;
        case 'histogram' :
            for(var i = 0; i < datas.length; i++) {
                 // Draw data another way.
            }
            break;
        }
    }
}

Now the computer isn’t repeating itself, but YOU are. And it is even worse. After all, the computer is done to do some work for you, not the other way around. Additionally, duplicating code is known as a bad practice. This is called the DRY principle : Don’t Repeat Yourself. Experience have showed us that duplicated code is harder to maintain, and is more bug prone. If you find a bug in the duplicated code, it have to be fixed at several place. You’ll sometime forget to correct it in one of the places. Eventually, the 2 duplication will evolve in 2 different implementation that require both to be maintained.

Here comes another good principle in programming : separation of concerns. Here we don’t want to care how to we traverse all our datastructure to apply our code on each data. Let’s delegate that work to another piece of code. This has 2 advantages : you avoid duplication of the loop, and by improving that traversal function, you’ll improve your whole codebase. You can improve it to make it faster, or to support new datastructures, or whatever your software will need in the future.

I’ll use the $.each function of jQuery here.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
function create_chart(type, datas) {
    switch(type) {
        case 'pie' :
            $.each(datas, function(i, data) {
                 // Draw the data in a way.
            });
            break;
        case 'histogram' :
            $.each(datas, function(i, data) {
                 // Draw data another way.
            });
            break;
        }
    }
}

Maybe this doesn’t look like a win to you, but it is, I can assure you. Now you have clearly separated the fact of traversing you datastructure and the action you’ll apply on it. But still we have some repetition, we have 2 identical calls to $.each . I’d say that is better but still not perfect.

Here, the whole point of our code is reduced to associate a closure with a keyword (pie or histogram) and pass this closure to $.each . To create this association, we will use an hashtable, and « TADAA ! » the Hashtable – closure pattern is born.

In javascript, every object is an hashtable, so let’s write some code :

1
2
3
4
5
6
7
8
9
10
function create_chart(type, datas) {
    $.each(datas, {
        pie : function(i, data) {
            // Draw the data in a way.
        },
        histogram : function(i, data) {
            // Draw data another way.
        }
    }[type]);
}

Implementation in PHP and D

You know everything, let’s go directly to code :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
function create_chart($type, $datas) {
    $closures = array(
        'pie'       => function($i, $data) {
            // Do stuff . . .
        },
        'histogram' => function($i, $data) {
            // Do other stuff . . .
        },
    );

    $closure = $closures[$type];
    foreach($datas as $i => $data) {
        $closure($i, $data);
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
void create_chart(R)(string type, R datas) if(isInputRange!R) {
    alias typeof(datas.front) T;
    auto closure = [
        "pie"       : function void(size_t i, T data) {
            // Do stuff . . .
        },
        "histogram" : function void(size_t i, T data) {
            // Do other stuff . . .
        },
    ][type];

    size_t i = 0;
    foreach(data; datas) {
        closure(i++, data);
    }
}

Both in PHP and D, foreach is a very extensible feature of the language. It will allow us to travers almost any datastructure.

Building on that pattern

In all our example, we use a string as a key for our hashtable. This is nice, but we can use actually anything. For performance reasons, an int is preferred. With an int, you can simply use an array (which is a special hashtable with identity as an hash function).

This pattern has another advantage, is make your code very extensible. In all presented examples, the hashtable is predefined. But you can perfectly store the hashtable outside the function and provide a way for third party code to add closure in it. Now you have a very nice design with a core library that can accept plugins to extends its functionality easily.

One thought on “The hashtable closure pattern

  1. This pattern is bog-standard in Python (which doesn’t have a switch statement precisely because this dictionary-based method dispatch is available).

    —————————–

    in the D:

    size_t i = 0;
    foreach(data; datas) {
    closure(i++, data);
    }

    may be idiomatically written as:

    foreach( i, data; datas) {
    closure(i, data);
    }

    where can be string for associative arrays, or size_t for int-indexed arrays. This also has the benefit of making the D code as short as the PHP 😀

Leave a Reply

Your email address will not be published. Required fields are marked *