blogstrapping

Why Use A C-Style For Loop?

Using C as the example language, I'll compare two ways to loop over an incrementing variable.

First, the for loop:

#include <stdio.h>

int counter, total;

int main() {
  total = 0;

  for (counter = 0; counter < 5; ++counter) {
    total += counter;
  }

  printf("The total is %d.\n", total);
}

Next, the while loop:

#include <stdio.h>

int counter, total;

int main() {
  counter = 0;
  total = 0;

  while (counter < 5) {
    total += counter;
    ++counter;
  }

  printf("The total is %d.\n", total);
}

A diff of the two versions is pretty simple:

5a6
>   counter = 0;
8c9
<   for (counter = 0; counter < 5; ++counter) {
---
>   while (counter < 5) {
9a11
>     ++counter;

Basically, the whole syntactic difference is that the for version combines three lines from the while version into one line. There is a pretty violent ongoing disagreement on the Web between two extreme camps with regard to line counts. One side says that line count is good (as a measure of verbosity), because it means your code is easier to read and understand. The other side says that line count is bad (as a measure of verbosity), because it means there is unnecessary complexity and bureaucratic overhead in the code. Both sides get some things right; their point of difference seems primarily to be where they focus on one good principle to the exclusion of another. Of course, most devleopers have a much more sophisticated and nuanced perspective, but many of those still tend to lean a bit too far in one direction or the other.

This looping code example -- simplistic though it may be -- is, I think, a pretty good example of where one of these two extreme camps gets something right.

Read the code for each out loud. When you are done, consider which of them would make the most sense to someone unfamiliar with C-style syntax, as a succinct plain-English explanation of what the code is doing, without adding a whole lot of text that is not immediately evident in the code. I think the explanations would go something like the following.

First, the for explanation:

"Total" starts at zero. For variable "counter" starting at zero, for counter less than five, increment counter. Add counter to total. Loop. Print total message.

Next, the while explanation:

"Total" starts at zero. Variable "counter" starts at zero. While counter is less than five, add counter to total. Increment counter. Loop. Print total message.

I don't know about you, but I think the second explanation is much clearer, and more easily translated into code in languages that do not use a C syntax with confidence that I am writing code that correctly produces the desired result. The interesting thing about that fact is, I think, that it does so while directly modeling the C syntax. In short, the while loop syntax more clearly and directly models the problem domain.

In this case, the greater verbosity camp is right, as far as pure syntactic clarity is concerned. The for loops appears to be little more than an utterly misguided bit of purpose-focused syntactic sugar. Its existence in the language, however, prompts one to use it where it seems like a natural fit -- makes it seem like the right tool for some jobs. Why would it exist, otherwise?

From where I am sitting, the only immediate syntactic downside to choosing the while loop is that, for sufficiently sophisticated operations within the loop, the while version separates the counter increment operation from the loop condition. This may be suboptimal in some way for grasping the code, but I am not entirely convinced.

I will keep my mind open to the possibility that a for loop makes for clearer code in some case, and if I find such a case I will use it, but otherwise my default will be the while approach. Counter-arguments are welcome.

Response

Brant Wedel replied in email. I made a couple of minor formatting edits and added a comment line to the C code example of a do/while loop in the second email to make it look a little better (to my eyes, at least). His commentary, with my responses attached, follows:

A counter argument is that anyone with basic proficiency in a programming language will be 'head wired' to understand a For loop, so assuming that people that know how to program in C are reading your C the For loop provides a better balance between readability, typing speed and understanding. This is especially true when people are thinking in the foreach mindset when looping through a collection of some number of elements it is largely unnecessary to actually worry about what is happening as far as counter variables and conditionals, it is better to have a for statement with a small comment (of course pointer arithmetic within a while loop over some more advanced list such as a linked list rather than a simple array easily breaks this point). . . . But in many cases from a readability viewpoint commenting a for loop to explain what is happening in the loop is vastly superior in readability to expanding the loop to a while loop especially for simple cases.

You could look at it from an instruction set viewpoint, the mind is not limited to x86 instructions, so coders have a hard wired pathway that can execute a for loop in one clock cycle where reading a while loop would take several mental cycles because of the scattered instruction parameters, like the counter being after the actual repeated block etc. these are things that I wouldn't imagine the brain would be as efficient at.

Anyway, while loops are great, but they aren't the end-all be-all of language readability and efficiency. I would hope that you use them where it its beneficial but use For loops where they are beneficial and comment more, a comment often is much better than expanded code especially where something trivial or common is taking place =P

He makes some good points. In reverse order:

  1. I do try to make sure I use the best construct for the job at hand, based on the circumstances of course, to ensure the most readable (and thus maintainable) code I can reasonably write. I do not dispute that the for loop might be preferable in some cases, given that it is already a standard part of the language. I do think it might have been better left out of the language, though. Note "might" in that sentence. I am still undecided.

  2. The reduction in mental clock cycles might be accomplished by a trade-off with state maintenance. It is often the case that you achieve reduced parsing complexity only at the expensive maintaining increased memory usage, and it seems to me that the potential reduction in the case of a for loop is often minimal in comparison to the fact that you have to remember for of its conditions while reading through the body of the loop to still come out the other end remembering how its iteration is handled. I'm not entirely sure abou this, though, and it may depend on the way the specific programmer thinks and juggles abstractions. This does not entirely contradict Brant's comment aboutary about mental cycles; it just cautions against assuming that necessarily means the for loop is the better choice all the time.

  3. I don't find that comments are a suitable replacement for clear syntax, generally speaking. Programmers get used to the for loop, so that it might look clear to those who use it regularly, but from a more objective perspective I think it takes a fairly cryptic form that must be memorized before it starts feeling clear and easy (which doesn't take long, but that step is still there). Comments actually clutter up code, particularly when they explain what you're doing rather than why you are doing it. I prefer keeping my comments succinct and limited to explaining why I do something (or making notes about stuff that needs to be changed on the next pass through, sometimes), ensuring clear ("self-documenting") code to convey the what-and-how of it.

    Of course, there is an argument to be made that the fact the crypticness of the for loop goes away for those used to reading it is all we need to justify its use, if there are other benefits (such as tighter representations of integrated pieces of code -- i.e., the increment, the condition, and the start value; such as encapsulation of the initial value within the loop syntax). After all, understanding requires at least basic knowledge of the language, and understanding the syntax of a for loop is pretty basic to the C language.

Brant sent another email, before I had written the above response:

Also you might include the

   do
   {
       /* do something */
   } while(true);

. . . possibly as a more accurate model of the domain, altho I almost never use it myself . . . probably because I'm hard wired to understand the while more than do-while and so the do-while is therefore more difficult to comprehend even if in reality sometimes its a more accurate model.

Also you might have inspired me to write my own blog/cms engine, I've been seriously looking at wordpress but I have been fighting with -- for non-blog reasons -- flexible demand scalability of cloud servers and wordpress may not be flexible enough for dynamic scaling by dynamic scaling I mean scaling up and down throughout the day to compensate for traffic on the fly on a hosted cloud platform (amazon ec2 for me). It seems the majority of information out there is for static scalability and of course MySQL has its limitations.

He makes an excellent point about the do/while loop, which appears to live in a blind spot for me, considering I did not once think of it while writing the original essay here, and even when it was pointed out to me I at first rebelled against the idea of it serving as a better syntactic expression of the computation model here than the while loop. There is a bit of a hiccup, however, in that the do/while ensures execution of the block of the loop itself at least once, which is not entirely obvious from the syntax, and might surprise an unwary programmer.

I'm heartened to hear that I'm inspiring people to write useful software, and I'll take this moment to urge Brant to write his own CMS rather than use WordPress. The popularity of WordPress is like that of PHP and MySQL, honestly; undeserved, and prone to creating problems later on down the line. His notion of dynamic scaling in a cloud deployment for a CMS sounds like a fun project to undertake, and I wish him luck.