Imperative Loops — Code Smells Catalog Skip to content

Imperative Loops

Also known as: Explicitly Indexed Loops, Indexed Loops, Loops

Functional Abusers Unnecessary Complexity Code Smell Within Class

for(i=0; i<len; i++) — the ceremony of manually tracking indexes, accumulating results, and handling off-by-one errors, when a map, filter, or built-in says the same thing in one line.

3 min read 2 sources

Overview

Martin Fowler has the feeling that loops are an outdated concept. He already mentioned them as an issue in his first edition of “Refactoring: Improving the design of existing code” book, although there were no better alternatives at that time. [1] Nowadays, languages provide an alternative - pipelines. Fowler, in his 2018 book (third edition), suggests that anachronistic loops should be replaced by pipeline operations such as filter, map, or reduce [2].

Indeed, loops can sometimes be hard to read and error-prone. This might be unconfirmed, but I doubt the existence of a programmer who has never had an IndexError at least once before. The recommended approach would be to avoid explicit iterator loops and use the forEach or for-in/for-of-like loop that takes care of the indexing, or Stream pipes. Still, one should consider whether he is not about to write Clever Code and check if there is already a built-in function that will take care of the desired operation.

I would abstain from specifying all the loops as code smells. Loops have always been and probably are still going to be a fundamental part of programming. Modern languages offer very tidy approaches to loops and even things like a List Comprehension in Haskell or Python. It is the indexation part might be the main problem. Of course, so are long loops or loops with side effects, but these are just a part of Long Method or side effects code smells.

However, it is worth taking what is good from functional languages (such as streams or the immutability of the data) and implement those as widely as possible and conveniently, to increase the reliability of the application.

Causation

It is impossible to easily overwrite the information given in the old books or video tutorials, which was pretty standard due to the lack of any other alternatives. People have learned that type of looping and may not even suspect that there are alternatives until they find them. Similarly, developers who come from older languages, which do not yet offer such facilities, can use explicit iteration habitually.

Problems

👁
Readability

In contrast to pipelines, loops don't provide declarative readability of what is precisely being processed.

Example

Explicitly Indexed Loop
1const examples = ['foo', 'bar', 'baz'];
2for (let idx = 0; idx < examples.length; idx++) {
3  console.log(examples[idx]);
4}
JAVASCRIPT
Clever Code, Flag and Explicit Iterator Loop
1const examples = ['foo', 'bar', 'baz'];
2let bar_in_examples = false;
3for (let idx = 0; idx < examples.length; idx++) {
4  if (examples[idx] == 'bar') {
5    bar_in_examples = true;
6  }
7}
8console.log(bar_in_examples); // true
JAVASCRIPT

Refactoring

  • Replace Loop with Pipeline
  • Replace Loop with built-in

Sources

Browse All 56 Smells