JavaScript Inner Functions

© 2012, Martin Rinehart

Today I'm working on a slider widget, the type with a handle that can set volume or the amount of red in a color. These lines of code are in the small .js file that supports this widget:

Just over 80 percent of the code is in inner functions. (None of them are used in closures.)

Inner functions are a part of JavaScript but none of JavaScript's major predecessors had them. When I first saw them I thought, "Oh, that's nice. But why?" Today I find them as fundamental as the ability to create objects.

Inner functions, once you understand functions, are simplicity itself. Let's begin at the beginning.

What Is a Function

In mathematics, Descartes introduced functions in the seventeenth century. Euler gave us our current notation a hundred years later: y = f(x).

In programming, Fortran (born 1957, see Genealogy of Programming Languages) used Euler's notation with two significant improvements: we could use more descriptive names (f and x don't really tell us much) and we could use as many arguments as needed. This JavaScript shell is typical of a function definition in all the languages in the massive Fortran family tree:

// compute a square root
function sqrt( number ) {
    var ret = ... /* computation */
    return ret;
}

The essence of a function was to isolate a computation, possibly a complex computation, in a single section of code that could be used whenever it was needed. In the classic case above, you could get a square root just by writing ... = sqrt( number );.

Functions

In the early days of Fortran, functions were used for mathematical functions: exponents, logarithms, trigonometric functions and so on. It was a great boon to scientists and engineers. The advantage of a pre-written module that did something common quickly led to a broader use of functions.

One of the functions in my current project draws a tic mark on the screen. It's not a computation in the mathematical sense but the idea is the same: set up a block of code that does something and then call that code whenever you need the thing done.

Terminology

Some languages reserve the name "function" for a set of statements that return a value. Names such as "subroutine" are used more broadly for any set of statements that can be executed as a unit.

Other languages, JavaScript included, use "functions" to name a group of statements, regardless of whether they return a value.

Why Functions

Dividing code into small, self-contained pieces has proven invaluable, for many reasons. If you have access to a function that computes a square root or draws tic marks you have one less thing to code (and one less source of bugs) to get your work done.

DRY

Before object-oriented techniques gained support in our languages, we spoke of "modular programming" techniques. The basic idea was to break a large program down into components that could be separately handled. "Modular programming" was a forgotten term when the Pragmatic Programmers invented the "DRY" (Don't Repeat Yourself) name. The principle is unchanged: write code once, whether it calculates square roots or draws tic marks, and call the routine whenever you need its functionality.

Organization

The more functionality that is moved out of a main program and into smaller, limited purpose routines, the better organized (and hence easier to read and maintain) the code will be.

Readability, ...

Better organization improves readability (the first step in program maintenance). Good functions help in many other ways, too. A function named sqrt() or draw_tic() immediately suggests its purpose.

What Is an Inner Function

A function that is defined within another function is called an "inner" function. (Similary, the containing function is called the "outer" function.) It looks like this:

function outer( outer_args ) {

    /* some work done here */

    function inner( inners_args ) {
        /* inner's work here */
    }

}

Why Inner Functions

Let's look at a skeletal example. We want to have a progress meter showing our site visitor how close to done something is. We'd like major tic marks every 20%, labelled, and minor tic marks every 5%, not labelled. Here's a function that will create tic marks for this progress meter (or for a themometer or for a slider that let's the user choose from 0 through 255 parts red, etc.).

function draw_tics( args... ) {

    /* pre-compute tic sizes, etc. */
    draw_major_tics( args );
    draw_minor_tics( other args );

    function draw_major_tics( ... ) {
        /*     draws tics,
            and labels them */
    }

    function draw_minor_tics( ... ) {
        /* tics, not labels */
    }

    function draw_a_tic( ... ) {
        /* used for both
            major and minor tics */
    }

}

This example shows how inner functions can be used to organize a larger process. If you wanted to improve the labels of the major tics, you would waste no time finding that bit of code.

It also shows how a common process, such as draw_a_tic(), can be separated out for use by the major and minor tic-drawing routines, but still not be part of the other code (which has no use for the fine art of drawing a tic mark).

The short answer to, "Why inner functions?" is the same as the answer to, "Why functions?". Let's take a quick look.

DRY 2

We had need in major and minor draw routines for a low-level routine that drew a single tic mark. We provided it in one place. We also extended "Don't Repeat Yourself" to add "But don't let others, who don't have the slightest interest, hear what you say."

Organization 2

Our code is well-organized in two dimensions: the structure of the code shows the process broken down into its component parts (drawing tics means drawing major, then drawing minor tics). It is also broken down into one section that worries about tic marks, and then there's the rest of the widget. Tic marks are separate.

Readability, ... 2

All these are maintenance concerns. If you need to improve the labels for the major tic marks, you could easily find the right bit of code within this skeleton. Just as important, if you are happy with the tic marks, but unhappy with something else, you can immediately set aside a big chunk of the code as "not today's problem." (Roughly, tic marks are about 150 of 400 lines of this widget's code.)

But Wait! There's More!

Can you have inner functions within inner functions? Yes. There is no limit.

Can you mix inner functions with objects? Yes. You could, for example, create a TicMark object that knew how to draw itself. The TicMark constructor could be an inner function within the draw_tic_marks() outer function. So could the TicMark.draw() method.

Objects within functions are perfectly reasonable in JavaScript. They would be an ideal solution if, for example, tic marks were used by just one type of widget in a widget set. Enclose them. (Need tic marks in several widgets? Don't enclose them in a widget.)

And, to be complete, can you use inner functions within constructors? Of course. If your constructor is non-trivial it may be best written with a set of inner functions.

Summary

When I first saw inner functions I wondered why they were useful. Today, I wonder why all languages don't have them.

By the by, my thermometer (an instance of the Meter class) now shows major and minor tics on the right, in Farenheit, and major and minor tics on the left, in Celsius.

If you're not using inner functions yet, just look at some of your own code. Got any functions that are a bit longer than others? I bet you could improve them with some smaller inner functions. Try it yourself and see what you think.


Feedback: MartinRinehart at gmail dot com.

# # #