Although they are one of the first constructs that junior programmers learn, loops can pose many potential issues the software development process, and could be avoided in many cases, according to Marco Emrich, of IT consulting firm Codecentric, speaking at this year’s OSCON conference, held earlier this month in Portland.
“If you are still writing loops, you’re not a bad person. Just think about whether you need to write loops or if there’s a better alternative,” he advised the crowd. Loops are best executed at the CPU level, well-beneath the concerns of most developers, he noted.
So before you start coding up that next do/while loop, consider the potential problems that have plagued writers of loops:
1: The One-off Problem: Here the programmer thinks they are having a loop execute something 10 times, when in fact it only executes nine times. Or 11. Think of “<=” (less than or equal to) instead of “<” (equal to). It is a subtle but frequent error and offer leads to developers to make “voodoo” with their code, by slightly changing the parameters to get the correct answer, while not fully understanding the actual logic driving the code.
2: Infinite Loops: When a program gets stuck and all the user can do is force the application to close, the likely culprit is an endless loop, a loop that continues to execute, never exiting. Like the one-off problem, these errors can be subtle. Emrich offered the example of a mistaken semicolon placed after a “while” statement that can cause a program never to get to the exit state of the loop.
3: Statefulness: Contrary to initial perceptions, loops are all tied up in state. “Loops are really stateful. I would say loops are almost state infested” Emrich said. This is problematic when it comes to debugging software, given that the code you have at runtime isn’t the same thing as what you see in your editor.
4: Hidden intent: In many cases, a loop construct can obscure what it was designed to do, or at least offer no visible evidence of what it is trying to do, resulting in the programmer (or another programmer) having to go back and reverse engineer its intent. “I can spend this time on more important issues,” Emrich said.
What are the alternatives to good old fashioned iteration?
Recursion is easier to understand, and with a few easy optimizations can be just as quick as loops. He cautioned that recursion is good for only a subset of problems, such as complex list operations, multidimensional problems, and for tree-based and graph algorithms.
Also look towards higher-order functions, which tackle the specific problem you are trying to solve, and also bring their own vocabulary, helping to make what you write understandable to others or to yourself at a later time (i.e. using a “filter” to obtain a subset of an array).
This takes care of the “hidden intent” issue: “So your program starts to become much more intentional,” he advised. A Map Function will apply a specific function (such as squaring a number) to all the elements of an array. The Stream API first introduced in Java 8 offers this capability. Using a mapping function “looks a little scary at first, because you need to convert the list into a stream, but it’s not that bad because you do it at the beginning and then have as many transformations as you like, and in the end you collect it back into an array,” Emrich said.
In a brief chat after the presentation, Emrich admitted his demonization of the looping construct was deliberately provocative, an effort o raise awareness that loops don’t always need to be used and that there are dangers in using them. He told us that he wishes now someone gave him these lessons when he got started.
When should you use loops then? When performance is critical, they can offer performance advantages. Even then, it’s important to look at where the performance bottleneck is, and it is rarely with the loop itself.
“Should loops actually die? The answer is: it depends. That’s the only answer you ever get in software development,” Emrich said.