Design Patterns – Coding Style for Chained Function Calls

design-patternsidiomsmethod-chainingstack-oriented

A common thing you need to do is to take a value, do something with it by passing it to a function, and then do some more with the return value, in a chain. Whenever I run into this type of scenario, I get unsure about how best to write the code.

As an example, let's say I have a number, num, and need to take the floored square root of it and turn it into a string. Here are a few possibilities (in JavaScript).

I might simply pass num to one function at a time, and replace num with the return value:

function floorSqrt(num) {
    num = Math.sqrt(num);
    num = Math.floor(num);
    num = String(num);
    return num;
}

This is nice since I don't need the original num any more, but in practice it might be confusing to start with one thing (a number) and end up with something completely different (a string).

I can save each step in a new variable:

function floorSqrt(num) {
    var sqrtNum = Math.sqrt(num);
    var floorSqrt = Math.floor(sqrtNum);
    var stringNum = String(floorSqrt);
    return stringNum;
}

Although it seems wasteful to declare all those variables and come up with good names for them.

Or I can just do it all as a one-liner:

function floorSqrt(num) {
    return String(Math.floor(Math.sqrt(num)));
}

But for more than two functions that approach gets incredibly unreadable, almost like code golf.

It seems to me like the most beautiful way to do this would be with some stack-based language, which might look something like this (pseudo code):

[sqrt floor toString]

Is there a way to do something similar with JavaScript? List some functions, run one at a time, and use the return value of each one as the argument for the next? The closest is how some libraries like jQuery or Underscore.js allow you to chain methods, something like this:

function floorSqrt(num) {
    return _.chain(num).sqrt().floor().toString().value();
}

I'm sure many wise people have thought wise things about this. What are some thoughts on pros and cons of the different styles?

Best Answer

TL;DR: The Reduce/Compose Functional Programming Idiom

# define/import: compose(fn1, f2)(arg) => fn2(fn1(arg)) 
# define/import: reduce(fn, [l1, l2, l3, ...]) => fn(fn(l1, l2), l3)...

commands = [Math.sqrt, Math.floor, String]
floorSqrt = reduce(compose, commands)

# floorSqrt(2) == String(Math.floor(Math.sqrt(2)))

Notes:

Using reduce and compose is a very common idiom used when you want to setup a pipeline of transformations for data to go through. It's both readable and elegant.

<rant> There are too many programmers who conflate readability with familiarity and vice versa. They believe an unfamiliar idiom is unreadable, like the reduce/compose idiom only because it is unfamiliar. To me this behavior is more aligned with a diletante, not someone who is serious about their craft. </rant>

Related Topic