DEV Community

Evgenii Ponomarev
Evgenii Ponomarev

Posted on • Originally published at evgenii.info on

When to Use Nested Functions

Warning: the word function appears more often than you are probably used to. Sorry.

When to Use Nested Functions

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

When to Use Nested Functions

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?

When to Use Nested Functions
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:

When to Use Nested Functions

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:

When to Use Nested Functions

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?

When to Use Nested Functions

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:

When to Use Nested Functions

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

When to Use Nested Functions

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:

When to Use Nested Functions

In this case, the alternative would be passing all arguments to reportError 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:

When to Use Nested Functions

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:

When to Use Nested Functions

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 :-)

Top comments (2)

Collapse
 
miketalbot profile image
Mike Talbot ⭐

Personally if I have to nest functions, I'll write the nested function after the actual main code of the routine. When I'm revisiting code I would rather read the purpose of the routine first rather than have my context screwed with looking at helper functions. 9 times out of 10 I don't need to look at those.

Collapse
 
parenttobias profile image
Toby Parent

Interesting and well written! Leads to ideas of composition, and how to pull the functionality you need in when you need it.

Another option to consider, and that might fit in nicely with this, is the ES6 module route. By defining your functionality inside the module script, it is still scoped to the exported (main) function, and can be used as needed in there.