Programming Practices – When to Daisy Chain Functions

functionsprogramming practicesreadability

In a program divided up into many functions by which it is intended that they execute themselves one after another, when (if ever) is it preferred to:

A) Execute the functions one after another in main()?

or

B) Execute one function in main(), and have that function daisy chain to the rest of the functions that need to be executed?


To illustrate this

Program FlowChart:

Start -> Make foo -> Do bar? -> True -> Say Goodbye -> End

A:

void makeFoo() {
    [...]
    return;
}
bool doBar() {
    bool bar;
    [...]
    return bar;
}
void sayGoodbye() {
    [...]
    return;
}
int main {
    makeFoo();
    if (doBar()) {
        sayGoodbye();
    }
    return 0;
}

B: (Daisy Chain)

void makeFoo() {
    [...]
    doBar();
    return;
}
void doBar() {
    bool bar;
    [...]
    if (bar) {
        sayGoodbye();
    }
    return;
}
void sayGoodbye() {
    [...]
    return;
}
int main {
    makeFoo();
    return 0;
}

Best Answer

Daisy chain when it is clear to the next developer why you did it that way.

"Code is read more often than it is written." -Guido von Rossum, PEP 008

There is no one answer to this, but I can give you a good rule of thumb: If the name of the function implies that its job is to do one function and call another, then it is safe to chain them.

There are times where two functionalities do really need to chain. Consider the classic example of error handling

result = doSomething();
if (result == badValue)
    haltAndCatchFire();

If this pattern shows up all the time, the next developer is going to get sore reading it over and over. Worse, they may get lazy or forget, causing unexpected results. However, haltAndCatchFire on its own is a pretty useful function to have, so we don't want to bury that functionality into doSomething, just to never see it again. As a solution:

doSomethingOrHaltAndCatchFire();

Its long, but now it is very clear that you intend to daisy chain. A developer who does not want to follow you into doSomething can generally assume that you'll call haltAndCatchFire if anything goes wrong, so you have successfully transmitted information to the next developer. They can keep reading main() without having to dodge and weave through multiple functions.

Your naming choice is up to you, as long as it is clear. As an example, on one suite of software I developed, there was a pattern:

int getValue();
int tryGetValue();

It was understood (social contract) that getValue() should call exception handling functions if something goes wrong. TryGetValue should just return (often returning a dummy value that let us know something went wrong). For other situations, where the social contract was not so clear, we had functions like getRegressionResultsForData(), which did some functions to get the data, then called getRegressionResults() on it.

In summary, you should never chain in a situation where a future developer could be mislead by skimming over a function (instead of diving into all sub-functions to look for chains).

Related Topic