Fundamental programming patterns I — Loops

help developers to write cleaner code

Heaton Cai
5 min readNov 28, 2021

We are often in a situation where I know every line of code does but have no idea what the program does. Many times, we have to piece many lines of code together in order to understand how the code behaves. Even sometimes due to too many lines of code, it is impossible to get the full picture of what are the business rules. Because of these unclean codes, the productivity of developers significantly drops. But is it possible to write code that is straightforward to readers so that they don’t need to run the code in their brains to understand the behaviour of the code? Is it possible to write code that only contain the information about the business rules (how it behaves) instead of the imperative control flows (how it runs)? Is it possible to write code that is just like a business document?

The answer is YES. And I have been doing this for many years. What we need is to constantly extract patterns and compose them to express the business logic.

In this series of articles, I’ll describe some fundamental programming patterns that help developers start the journey to declare business logic and remove imperative control flows from the code. You might have already noticed that it is about declarative programming paradigm. It is true and I will be focusing on showing the connection between imperative programming and declarative programming and why the latter is a better option for software applications.

Short version of this article

Essentially, the reason we need loops is to get a result by folding elements from a collection. Thus, we can use function fold as a cleaner way than loops to implement business logic.

Note: the examples in this article are written in Kotlin.

Loops

Loops are one of the most common control flows in programming languages to repeat some particular code until a specific condition is fulfilled. It is also the basis of other patterns. Let’s have a look.

A commonly used example to illustrate loops is to add numbers from 0 to n (n ≥ 0). It is mainly used in the rest of this article. You will see how the code evolves and gets better and better versions of the function sum.

Goto

Decades ago, using goto statements is very common to control a repetitive flow. Check the following code:

int s = 0;
int i = 0;
loop:
s += i++;
if(i <= n) {
goto loop;
}
return s;

This code is hard to read because the scope of a loop isn’t straightforward. To improve that, while can be introduced.

While

Many years ago, while statements are the most popular alternative to replace goto . Check the code below:

The condition and the scope of a loop are much clearer than goto. However, it is still not easy enough to read because the key variable i of the loop is used in 3 places. Thus for is introduced to allow us to declare i within the scope of the loop and separate the loop from the calculation rules.

For

In many popular languages, for statements are still commonly used. Check the following code (not in Kotlin since it doesn’t support the traditional for statement):

int s = 0;
for (i = 0; i <= n; i++) {
s += i;
}
return s;

It is much better than while because it separates the logic from the loop. However, going through the numbers from 0 to n is also part of the logic, which is still part of the for loop. To split them completely, we can create a range from 0 to n, then iterate each element in the range to add them together. Check the code:

0..n represents a range from 0 to n (inclusive). This version is again clearer than the preview one. But 0..nis still part of the loop. It isn’t natural for humans to read since we normally scan from left to right. An alternative to replace the for statement to make it more natural:

So far, we have made a lot of improvements. But we still need to read 4 lines to understand the behaviour. Are there better ways?

Recursion

A recursive function in programming is a function calls itself. So a function gets repeated as other loops. To implement sum with recursion, we can think that sum(n) = sum(n-1) + n .

sum(n) = sum(n-1) + n

We also need an exit condition. In this case, it is sum(0) = 0 . So here is the code:

Recursive functions repeat themselves and accumulate the results until a specific condition is fulfilled. It is a declarative way to implement loops. In this case, we are able to remove all the imperative control flows and only remains the calculation rule. However, many languages don’t support recusions well, so we need more ways to declare the logic.

Collection

So far, we have seen many ways to implement loops. The reason we need loops is that there is a collection of elements (0 to n) and we want to apply some logic to each element. Here is another example:

join a list of strings

If we compare loops to loops, we’ll find that many loops are basically a pattern that gives an initial state and accumulates each element in a collection from first to last or from last to first.

compare for loop
compare recursion

As we see, they have a lot in common. The code is just like folding elements together. So let’s call the pattern fold .

Fold

A generic fold method looks like this:

fold elements from first to last

Most languages have already implemented the method (might be called differently, such as reduce in Javascript). However, it is important to understand that the essence of the method is a loop so that we are able to use it properly. For example, the sum method:

This version is again clearer than before.

Fold Right

This is similar to fold but in the opposite direction.

fold from last to first

fold and foldRight are two very basic patterns that can be used to replace for loops in most cases. They are also the basis of all other fundamental collection patterns that I’ll introduce in my following articles.

Summary

The loop is one of the most commonly used patterns to help to express business logic, such as transform data, split or merge data, calculate data, etc. However, the loop itself doesn’t have value, it has to be combined with other code (such as sum += i) to be valuable. By replacing it with fold , we can declare the behavior as a whole so that the readers can easily understand.

--

--

Heaton Cai

16 years in the IT industry, passionate to share what I have learnt. All thoughts and opinions are original and maybe new. Free to share with the original link.