When to Use Nested Functions

Resilient Software Jun 10, 2021
Warning: the word function appears more often than you are probably used to. Sorry.

Alright, let's begin: nested functions are functions defined inside other functions (promised and delivered). You saw them in many forms, like this one:

Here, the function multiply is defined inside its parent, pow, although it does not have to be this way.

Or does it? If nothing else uses multiply, are there any reasons to move it out?

Tough choice

This topic regularly ignites lengthy bike-shedding conversations regardless of the programming language (stack overflow about python, reddit about swift), so I want to jump in and list some more pros and cons which you can apply for your needs.

Why you should not use nested function

Nested functions reduce readability

The bigger a function is, the harder it is to read it.
Look at this example:

By defining three additional functions inside showNews, you make the reader's job harder: they have to scan all of them before reaching the part with actual logic.

It might be much shorter:

The reader still can jump to any functions to see how they work, but now it's optional.

Nested functions influence future growth

One may argue that not all nested functions affect readability.

In the previous example, you had three big helpers — pretty bad. What if there was only one?

Does having loadNews inside the primary function cause any harm? After all, it is just several extra lines.

The danger of this approach shows itself when someone needs to add more functionality. You should not be surprised when your colleagues follow the same style and add other nested functions next to the existing one. After all, they just follow the rules you defined as an author.

All it takes to degrade a good codebase is one example of a poor pattern and people's intent to maintain the code style.

Check the article about "Reckless Reuse" for more examples of how code becomes unmaintainable without anyone noticing.

When nested functions are good

Now you may have an idea that all nested functions are evil and should be avoided by any means.

This is not true.

In some cases, they bring some benefits that can outweigh the disadvantages.

Sometimes you do not want others to use your functions

Yes, functions are meant to be reused. But you may not want it, e.g. if a function handles your particular case but is not suitable for everyone:

There are many cases in which isEqual returns an unexpected result:

But it may be the exact behaviour you need.

In this case, it will be safer to define this function inside saveNews so that nobody has to deal with its peculiarities.

Sometimes you need access to an outer scope

Many languages give nested functions access to the variables from the parent scope and even allow to modify them. You may need to explicitly declare such variables (Python) or capture them by reference (C++), but the benefits are the same:

In this case, the alternative would be passing all arguments to handleError every time we call it, using Function.prototype.bind or wrapping it into a factory. While I prefer different things depending on the situation, I see why somebody may use nested functions here.

Some implementation details are helpful

From the reader's point of view, there are few things worse than jumping between functions to understand how the whole thing works.

Try to understand this piece:

The functions onSuccess and onError do not only hide implementation details but also obscure their purpose. You know something happens, but you don't know what exactly.

In this case, it would be better to define onSuccess and onError within the primary function so that the reader knows what is happening without leaving it:

Two things to note here:

  • Implementation details are still hidden: you know what is happening but not how
  • Try to avoid situations like this by better naming and defining better APIs. The downsides of nested functions are still there.

So, what to do?

I usually try to avoid nested functions because they make their parents bigger and, as a result, harder to read. Even if a nested function is concise and the impact is negligible, it can potentially become a slippery slope and serve as a bad example for adding similar ones.

But, as you can see, there are some situations when going this path does worth the downsides.

I hope that now you can defend any side in this holy war and justify the style you prefer. Happy coding!


As always, you can subscribe to Resilient Systems and receive new articles by email if you haven't done it yet.
You also can find me on Twitter or somewhere else – I am always happy to chat :-)

Tags

Evgenii Ponomarev

Blogging about long-living systems and common sense. All opinions belong to me, my wife and my cat

Great! You've successfully subscribed.
Great! Next, complete checkout for full access.
Welcome back! You've successfully signed in.
Success! Your account is fully activated, you now have access to all content.