Take the 2-minute tour ×
Programmers Stack Exchange is a question and answer site for professional programmers interested in conceptual questions about software development. It's 100% free, no registration required.

Say you have the following forloop*:

for (int i = 0; i < 10; ++i) {
    // ...
}

which it could commonly also be written as:

for (int i = 0; i != 10; ++i) {
    // ...
}

The end results are the same, so are there any real arguments for using one over the other? Personally I use the former in case i for some reason goes haywire and skips the value 10.

* Excuse the usage of magic numbers, but it's just an example.

share|improve this question
8  
The superior solution to either of those is to use the arrow operator: int i = 10; while(i --> 0) { /* stuff */ } –  corsiKa Apr 25 '11 at 17:11
    
@glowcoder the arrow operator is my favorite –  Carson Myers Apr 25 '11 at 17:15
2  
@glowcoder, nice but it traverses from the back. You may not always want that. –  user1249 Apr 25 '11 at 17:49
2  
@SuperElectric, it parses like while ((i--) > 0) –  Kristopher Johnson Apr 25 '11 at 18:53
10  
There is a (probably apocryphal) story about an industrial accident caused by a while loop testing for a sensor input being != MAX_TEMP. Unfortunately one day the sensor input went from being less than MAX_TEMP to greater than MAX_TEMP without every passing through MAX_TEMP. The process overheated without being detected, and a fire ensued. Sometimes there is a difference between != and <. –  Charles E. Grant Apr 26 '11 at 0:34
show 1 more comment

10 Answers

up vote 51 down vote accepted

The reason to choose one or the other is because of intent and as a result of this, it increases readability.

Intent: the loop should run for as long as i is smaller than 10, not for as long as i is not equal to 10. Even though the latter may be the same in this particular case, it's not what you mean, so it shouldn't be written like that.

Readability: a result of writing down what you mean is that it's also easier to understand. For example, if you use i != 10, someone reading the code may wonder whether inside the loop there is some way i could become bigger than 10 and that the loop should continue (btw: it's bad style to mess with the iterator somewhere else than in the head of the for-statement, but that doesn't mean people don't do it and as a result maintainers expect it).

share|improve this answer
3  
No, the loop should not run as long as i is “smaller than 10”, it should run as long as the (in this case) upper bound is not reached. When using the C++ interval / iterator range rationale, it’s far more logical to express this via != than <. –  Konrad Rudolph Apr 25 '11 at 11:34
13  
@Konrad I don't disagree with that at all. The main point is not to be dogmatic, but rather to choose the construct that best expresses the intent of the condition. And so, if you choose to loop through something starting at 0 and moving up, then < actually expresses that precisely. –  Deckard Apr 25 '11 at 11:36
4  
@Konrad, you're missing the point. The increment operator in this loop makes it obvious that the loop condition is an upper bound, not an identity comparison. If you were decrementing, it'd be a lower bound. If you're iterating over a non-ordered collection, then identity might be the right condition. –  Alex Feinman Apr 25 '11 at 15:56
2  
@Alex the increment wasn’t my point. An interval doesn’t even necessarily have an order. It just iterates over … well, something until it reaches the end. For example, elements in a hash set. In C++, this is done using iterators and a for loop. Using < here would be silly. Also, Deckard seems to acknowledge that. I very much agree with his comment in response to mine. –  Konrad Rudolph Apr 25 '11 at 16:04
1  
Note, if you use a rotary buffer with chase pointers, you MUST use != –  SF. Jul 28 '11 at 7:19
add comment

The < pattern is generally usable even if the increment happens not to be 1 exactly.

This allows for a single common way to do loops regardless of how it is actually done.

share|improve this answer
5  
It also allows i to modified inside the loop totally safely if need be. –  Matthew Scharley Apr 25 '11 at 13:10
1  
or if 'i' is modified totally unsafely... Another team had a weird server problem. It kept reporting 100% CPU usage and it must be a problem with the server or the monitoring system, right? No, I found a loop condition written by a 'expert senior programmer' with the same problem we're talking about. –  james Apr 25 '11 at 14:09
11  
Except that not all C++ for loops can use <, such as iterators over a sequence, and so != would be a single common way to do loops in C++. –  David Thornley Apr 25 '11 at 15:01
    
@SnOrfus: I'm not quite parsing that comment. You won't in general reliably get exceptions for incrementing an iterator too much (although there are more specific situations where you will). –  David Thornley Apr 25 '11 at 17:00
    
Well, I follow the < pattern because it requires one keystroke instead of two with the > pattern, and four with !=. It's a matter of OCD-like efficiency really. –  Spoike Aug 17 '11 at 8:17
show 1 more comment

In C++ the recommendation by Scott Myers in More Effective C++ (item 6) is always to use the second unless you have a reason not to because it means that you have the same syntax for iterator and integer indexes so you can swap seamlessly between int and iterator without any change in syntax.

In other languages this does not apply so I guess < is probably preferable because of Thorbjørn Ravn Andersen's point.

By the way, the other day I was discussing this with another developer and he said the reason to prefer < over != is because i might accidentally increment by more than one, and that might cause the break condition not to be met; that is IMO a load of nonsense.

share|improve this answer
14  
"load of nonsense"... until the day you accidentially have an extra i++ in the body of the loop. –  user1249 Apr 25 '11 at 10:13
10  
@B Tyler, we are only human, and bigger mistakes have happened before. Consider < to be more defensive programming than != then... –  user1249 Apr 25 '11 at 12:03
2  
@Thorbjørn Ravn Andersen - I'm not saying that I don't agree with you, I do; < is more defensive and my colleagues hate it if I write != so I don't. However, there is a case for != in C++ and that is what I've presented. –  user23157 Apr 25 '11 at 12:48
8  
One scenario where one can end up with an accidental extra i++ is when changing a while loop into a for loop. Not sure that having half the number of iterations is any better than a (near-)infinite loop though; the latter would probably make the bug more obvious. –  ak2 Apr 25 '11 at 13:33
2  
+1. +10 if I could. The choice is language-dependent because of C++'s peculiarities. Don't change your loop variable in the body of your loop. –  Carl Manaster Apr 25 '11 at 15:08
show 5 more comments

Here is one reason why you might prefer using < rather than !=. If you are using a language which has global variable scoping, what happens if other code modifies i? If you are using < rather than !=, the worst that happens is that the iteration finishes quicker: perhaps some other code increments i by accident, and you skip a few iterations in the for loop. But what happens if you are looping 0 through 10, and the loop gets to 9, and some badly written thread increments i for some weird reason. Then your loop finishes that iteration and increments i so that the value is now 11. As the loop has skipped the exit condition (i never equalled 10) it will now loop infinitely.

It doesn't necessarily have to be particularly freaky threading-and-global-variables type logic that causes this. It might just be that you are writing a loop that needs to backtrack. If you are mutating i inside the loop and you screw your logic up, having it so that it has an upper bound rather than a != is less likely to leave you in an infinite loop.

share|improve this answer
3  
Of course, this seems like a perfect argument for for-each loops and a more functional programming style in general. But, why would you want to do that when mutable variables are so much more fun?! –  Tom Morris Apr 25 '11 at 10:04
3  
I don't think that's a terribly good reason. Either way you've got a bug that needs to be found and fixed, but an infinite loop tends to make a bug rather obvious. –  ak2 Apr 25 '11 at 13:37
add comment

Using "less than" is (usually) semantically correct, you really mean count up until i is no longer less than 10, so "less than" conveys your intentions clearly. Using "not equal" obviously works in virtually call cases, but conveys a slightly different meaning. In some cases this may be what you need but in my experience this has never been the case. If you really did have a case where i might be more or less than 10 but you want to keep looping until it is equal to 10, then that code would really need commenting very clearly, and could probably be better written with some other construct, such as a while loop perhaps.

share|improve this answer
add comment

In terms of CPU cycles, != will be a faster test than <, so over (thousands) of iterations, this may result in a slight performance increase. This could be one reason to favour that pattern, particularly in tight loops in performance-critical situations (eg: particle system broad sweep updates).

share|improve this answer
3  
Why is '!=' faster than '<'? –  oosterwal Apr 25 '11 at 16:33
3  
If that's true, it certainly architecture-dependent. An x86 architecture, for instance, can combine a CMP (compare) with a JNE (jump if not equal) instruction into one "macro" instruction. That kind of optimization is done at the hardware level. Compilers also do optimization. You just can't make a blanket statement like this without a profiler. In any case, the compiler and hardware should work for the programmer, not the other way around. –  Scott Whitlock Apr 25 '11 at 16:49
    
Ouch that's a lot of downvotes. I should just keep my yap shut. I'm surprised that a JNL would execute as fast as a JNE, but I suppose every opcode executes at the same speed. –  Tom Auger Apr 27 '11 at 2:23
    
@Tom: A conditional jump doesn't compare the numbers -- that's already done by the immediately preceding compare, which sets all the same flags either way. A conditional jump just checks the flags that were set (ZF usually meaning "equal", and the overflow/carry/sign flags working together to mean greater/less or above/below), and jumps (or not) depending on those flags. It does pretty much the same amount of work either way, and thus doesn't need any extra time to do it. –  cHao Oct 7 '11 at 19:56
add comment

Using (i < 10) is in my opinion a safer practice. It catches the maximum number of potential quitting cases--everything that is greater than or equal to 10. Contrast this with the other case (i != 10); it only catches one possible quitting case--when i is exactly 10.

A byproduct of this is that it improves readability. Additionally, should the increment be anything other 1, it can help minimize the likelihood of a problem should we make a mistake when writing the quitting case.

Consider:

1) for (i = 1; i < 14; i+=2)

2) for (i = 1; i != 14; i+=2)

Although both cases are likely flawed/wrong, the second is likely to be MORE wrong as it will not quit. The first case will quit, and there is a higher chance that it will quit at the right spot, even though 14 is probably the wrong number (15 would probably be better).

share|improve this answer
    
The first case may be right! If you want to iterate over all natural numbers less than 14, then there's no better way to to express it - calculating the "proper" upper bound (13) would be plain stupid. –  maaartinus Apr 25 '11 at 19:52
add comment

One reason why I'd favour a less than over a not equals is to act as a guard. In some limited circumstances (bad programming or sanitization) the not equals could be skipped whereas less than would still be in effect.

Here is one example where the lack of a sanitization check has led to odd results: http://www.michaeleisen.org/blog/?p=358

share|improve this answer
add comment

Here's another answer that no one seems to have come up with yet. for loops should be used when you need to iterate over a sequence. Using != is the most concise method of stating the terminating condition for the loop. However, using a less restrictive operator is a very common defensive programming idiom. For integers it doesn't matter - it is just a personal choice without a more specific example. Looping over collections with iterators you want to use != for the reasons that others have stated. If you consider sequences of float or double, then you want to avoid != at all costs.

What I wanted to point out is that for is used when you need to iterate over a sequence. The generated sequence has a starting point, an interval, and a terminating condition. These are concisely specified within the for statement. If you find yourself either (1) not including the step portion of the for or (2) specifying something like true as the guard condition, then you should not be using a for loop!

The while loop is used to continue processing while a specific condition is met. If you are not processing a sequence, then you probably want a while loop instead. The guard condition arguments are similar here, but the decision between a while and a for loop should be a very conscious one. The while loop is under-appreciated in C++ circles IMO.

If you are processing a collection of items (a very common for-loop usage), then you really should use a more specialized method. Unfortunately, std::for_each is pretty painful in C++ for a number of reasons. In many cases separating the body of a for loop in a free-standing function (while somewhat painful) results in a much cleaner solution. When working with collections, consider std::for_each, std::transform, or std::accumulate. The implementation of many algorithms become concise and crystal clear when expressed in this manner. Not to mention that isolating the body of the loop into a separate function/method forces you to concentrate on the algorithm, its input requirements, and results.

If you are using Java, Python, Ruby, or even C++0x, then you should be using a proper collection foreach loop. As C++ compilers implement this feature, a number of for loops will disappear as will these types of discussions.

share|improve this answer
1  
"However, using a less restrictive operator is a very common defensive programming idiom." This sums it up more or less. –  James Poulson Apr 25 '11 at 14:03
    
+1 for discussin the differences in intent with comparison to while, for, and foreach(or language equivilant) –  Kevin Peno Apr 25 '11 at 15:08
    
Strictly speaking, the while loop is used to continue processing until a specific condition is not met –  Alnitak Apr 16 '12 at 20:02
    
@Alnitak - D'oh ... I'll fix that :) –  D.Shawley Apr 21 '12 at 12:10
add comment

In the embedded world, especially in noisy environments, you can't count on RAM necessarily behaving as it should. In a conditional (for, while, if) where you compare using '==' or '!=' you always run the risk that your variables skipped that crucial value that terminates the loop--this can have disasterous consequences--Mars Lander level consequences. Using '<' or '>' in the condition provides an extra level of safety to catch the 'unknown unknowns'.

In the original example, if i were inexplicably catapulted to a value much larger than 10, the '<' comparison would catch the error right away and exit the loop, but '!=' would continue to count up until i wrapped around past 0 and back to 10.

share|improve this answer
1  
Another related variation exists with code like for (i=4; i<length; i++) csum+=dat[i]; where legitimate packets would always have a length of at least four, but one might receive corrupted packets. If different packet types have different length requirements, one may wish to validate the length as part of the processing that's different for each packet type, but validate the checksum as part of the common logic first. If an under-length packet is received, it doesn't really matter whether the checksum computation reports "good" or "bad", but it shouldn't crash. –  supercat Aug 13 '12 at 18:11
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.