Is there a technical reason to use > (<) instead of != when incrementing by 1 in a 'for' loop?

14,729

Solution 1

while (time != 6:30pm) {
    Work();
}

It is 6:31pm... Damn, now my next chance to go home is tomorrow! :)

This to show that the stronger restriction mitigates risks and is probably more intuitive to understand.

Solution 2

There is no technical reason. But there is mitigation of risk, maintainability and better understanding of code.

< or > are stronger restrictions than != and fulfill the exact same purpose in most cases (I'd even say in all practical cases).

There is duplicate question here; and one interesting answer.

Solution 3

Yes there is a reason. If you write a (plain old index based) for loop like this

for (int i = a; i < b; ++i){}

then it works as expected for any values of a and b (ie zero iterations when a > b instead of infinite if you had used i == b;).

On the other hand, for iterators you'd write

for (auto it = begin; it != end; ++it) 

because any iterator should implement an operator!=, but not for every iterator it is possible to provide an operator<.

Also range-based for loops

for (auto e : v)

are not just fancy sugar, but they measurably reduce the chances to write wrong code.

Solution 4

You can have something like

for(int i = 0; i<5; ++i){
    ...
    if(...) i++;
    ...
}

If your loop variable is written by the inner code, the i!=5 might not break that loop. This is safer to check for inequality.

Edit about readability. The inequality form is way more frequently used. Therefore, this is very fast to read as there is nothing special to understand (brain load is reduced because the task is common). So it's cool for the readers to make use of these habits.

Solution 5

And last but not least, this is called defensive programming, meaning to always take the strongest case to avoid current and future errors influencing the program.

The only case where defensive programming is not needed is where states have been proven by pre- and post-conditions (but then, proving this is the most defensive of all programming).

Share:
14,729

Related videos on Youtube

Zingam
Author by

Zingam

Updated on July 14, 2022

Comments

  • Zingam
    Zingam almost 2 years

    I almost never see a for loop like this:

    for (int i = 0; 5 != i; ++i)
    {}
    

    Is there a technical reason to use > or < instead of != when incrementing by 1 in a for loop? Or this is more of a convention?

    • barak manos
      barak manos almost 9 years
      It makes it more readable, plus, if you ever change i++ to i+=2 (for example), it will run for a very long time (or possibly forever). Now, since you typically use < for those cases where you increment the iterator by more than 1, you might as well use < also for the case where you increment it by 1 (for consistency).
    • Slava
      Slava almost 9 years
      5 != i is evil
    • Werner Henze
      Werner Henze almost 9 years
      No technical reason. Just a question of style/preference.
    • alk
      alk almost 9 years
      ... and robustness of the code. @WernerHenze
    • Zingam
      Zingam almost 9 years
      @barakmanos I would argue that if you are making such a change later you should really know what you are doing and do it properly and check all checks and conditions.
    • dgo
      dgo almost 9 years
      I agree with Zingam regarding the later change and being conscious of your actions, but I think @barakmanos makes a valid point.
    • Marc Glisse
      Marc Glisse almost 9 years
      != is necessary when iterating over some more complicated types, so people can be tempted to use it everywhere. On the other hand, IIRC openmp requires < to parallelize a loop.
    • Aurast
      Aurast almost 9 years
      You should always be conscious of what you're doing, but you will make mistakes anyway. Using < reduces the possibility of someone introducing a bug into this code.
    • Ole Tange
      Ole Tange almost 9 years
      Your example uses int. If it used float you may hit one of the floating number that are almost but not quite == the other number (similar to 1.99999 == 2.0). < would guard against this kind of problems. But if the increment is always 1 then you are not likely to see this kind of problems either. Only if you increment is more complex you might run into that.
    • CaptainCodeman
      CaptainCodeman almost 9 years
      @OleTange If you are iterating using floating point numbers you are already screwed..
    • user3528438
      user3528438 almost 9 years
      for loop is pre-test, so there's not a lot of difference. I came across a piece of asm code that does post-test but still uses != (yes, JNE), the very ugly thing is that, when trip count is 0, the first iteration still runs, loop counter is incremented so !=0, then condition is true for(almost)ever.
    • Nicholas Carey
      Nicholas Carey almost 9 years
      @Slava...not evil. You've apparently never been bit in C by a simple typo making the difference between if ( i == 5 ) ... and if ( i = 5 ). Very different things. Reversing the operands prevents the problem: since literals are not lvals, they can't be assigned to and the compiler hurls on the typo. @Zingam: good defensive programming!
    • Slava
      Slava almost 9 years
      @NicholasCarey I've been hit with that problem. Issue is you try to prevent a bug that is easy to catch and may produce bugs that are hard to catch.
    • Hot Licks
      Hot Licks almost 9 years
      As a programmer for 50 years (started with FORTRAN) I can say that using < helps prevent a lot of problems, in part because it makes you think a little more about what you're coding. Yes, it can hide some problems as well, but it's a worthwhile tradeoff.
    • pyrocrasty
      pyrocrasty almost 9 years
      @CaptainCodeman Actually, a simple integer loop like this should still work with a float variable. Not that I'd recommend it! (Really, for floats, equality is just for comparing a variable with its prior value to see if it has been touched)
    • Antonio
      Antonio almost 9 years
      @NicholasCarey I have personally always been saved by a compiler warning in those cases.
    • faridSam
      faridSam almost 9 years
      @OleTange You (almost) never use a floating point variable as a loop counter for the very reason you mention – floating point variables are inexact for many values and the errors will accumulate.
    • Kickstart
      Kickstart almost 9 years
      Many years ago in Mainframe days using PL/1 with CICS I fell for this with a loop. Checking that the loop counter wasn't equal to 17, and if not incrementing the counter. But a bug elsewhere meant very occasionally the loop started at 18, so the loop carried on for ages. As the counter was used as a subscript for an array it was updating it carried on writing to storage, until it hit something important (the system table listing the entry points for various programs) and brought CICS down.
    • Toni Leigh
      Toni Leigh almost 9 years
      @Slava - what is evil about 5 == i ?
    • Slava
      Slava almost 9 years
      @ToniLeigh in short: 5.operator==( i ) fails. It is even worse if i has implicit conversion operator.
    • Toni Leigh
      Toni Leigh almost 9 years
      @Slava - I must say I've never seen 5.operator==( i ) in any language I've used, how is it related to 5 == i ?
    • Slava
      Slava almost 9 years
      @ToniLeigh if i is an instance of class that has operator==(int) then statement i == 5 would compile, but 5 == i would fail. If i has operator double() then 5.0 == i would produce difficult to catch bug.
    • Toni Leigh
      Toni Leigh almost 9 years
      @Slava fair enough, but this case sounds somewhat unusual, perhaps in the context given it's evil, but generally it's a good catch for something equally pernicious - the accidental assignment of 5 to i resulting from the typo i = 5
    • Slava
      Slava almost 9 years
      @ToniLeigh main problem that i = 5 is easy to catch and IMHO all modern compilers generate warning for it, case like implicit double would not have any warnings and difficult to catch - it may work in some cases. Irony is main reason OP asked this question because 5 > i would be even worse, so he wants to keep constant on the left and that implies != instead of < or >
    • eversor
      eversor almost 9 years
      5 != i that a yoda condition is
    • Gianluca Ghettini
      Gianluca Ghettini almost 9 years
      yes.. reversing the operands is quite useful.. literals are not lvals so if you make a typo and write 5 = i you will get a syntax error. YODA conditions helpful are!!!!!!!!!!!!
    • Admin
      Admin over 8 years
      Yoda talk unfamiliar to me. Yoda code me no like. Idiomatic, good is, no hate code 2 years later when idiomatic it is. Like everything else, it looks. Testing care takes, of rest.
    • Adrian McCarthy
      Adrian McCarthy over 8 years
      I'd argue that this is not a duplicate because: (1) the other question is asking specifically about efficiency and this one is open to technical reasons for doing or not doing this, and (2) the other question is asking about a broader swath of languages and thus is less likely to deal with language-specific issues (like C++ iterators).
    • Zingam
      Zingam over 8 years
      @Slava Yesterday VC++ 2015 didn't warn me about if (variable = constant) :) I have a difficulty understanding your example why 5 == i that evil. If I ask a question - would you mind to elaborate more thoroughly?
    • Slava
      Slava over 8 years
      @Zingam I am not sure if such question would be applicable to SO as it answer could be opinion based.
    • Adrian McCarthy
      Adrian McCarthy over 8 years
      Unfortunately, the "duplicate" question also conflates a second issue (pre- v. post-increment) and focuses on the efficiency of that.
    • Lundin
      Lundin over 6 years
      The duplicate is a bad question in general, it brings in all manner of different languages. C++ specifically has the issue of operator overloading - a reason to pick one operator over the other might be to reduce the amount of operators that you need to overload. I'll re-open this.
    • Kuba hasn't forgotten Monica
      Kuba hasn't forgotten Monica over 5 years
      Re floats: on all sensible implementations, floats represent integers exactly until you overflow the range of mantissa. On most platforms where sizeof(double) > sizeof(int), a double can hold integers larger than what fits into an int.
  • Ely
    Ely almost 9 years
    Nice example. I'd be interested in a case for != instead of <. I personally never used that I think.
  • 463035818_is_not_a_number
    463035818_is_not_a_number almost 9 years
    @Elyasin I didnt find a good one, and I didnt want to post a bad one: Imagine you have some kind of circular container, where you increment by +x modulo the size of the container N and you want to stop the loop when you reach a certain index.... well thats a really bad example. Maybe I will find a better one
  • 463035818_is_not_a_number
    463035818_is_not_a_number almost 9 years
    you may be right on the number of overloads, but when considering the requirements on the objects, then for almost any object one can define a != operator, but it is not always possible to define a strict weak ordering. In this sense != would be better, because it puts less requirements on the type. However, I still stay with the <.
  • Paul Smith
    Paul Smith almost 9 years
    The same loop with != instead of < makes it clear what the advantage of < (or >) is in this context. for (int i=a; i != b; i++) {}
  • WernerCD
    WernerCD almost 9 years
    This type of inner "if (condition) then i++" is the first thing I thought of.
  • Adrian McCarthy
    Adrian McCarthy almost 9 years
    Sometimes, attempting to "mitigate risks" just ends up hiding the bug. If the design of the loop should preclude the 6:30 p.m. from slipping by unnoticed, then using < will hide the bug but using != would make it obvious that there's a problem.
  • Lightness Races in Orbit
    Lightness Races in Orbit almost 9 years
    @AdrianMcCarthy: Not necessarily; it could just introduce a second bug, making diagnosis harder.
  • Adrian McCarthy
    Adrian McCarthy almost 9 years
    @LightnessRacesinOrbit: I've yet to see an instance of that. Remember, I said, "If the design of the loop should preclude the 6:30 p.m. from slipping by unnoticed...."
  • Lightness Races in Orbit
    Lightness Races in Orbit almost 9 years
    @AdrianMcCarthy: That's kind of my point; you could have a few instances of it that you haven't seen yet ;)
  • Dan Getz
    Dan Getz almost 9 years
    The logic is perfectly fine. When i is 5 the loop exits. Did you mean to say something else?
  • emory
    emory almost 9 years
    This is an excellent example, but I was thinking of the case where b changed in the loop. I am not sure for(int a=1; a!=b;i++){ b-=2;} terminates.
  • Markus
    Markus almost 9 years
    If the data does not get transferred to correctly due to heat, electro.magnetic influences your code runs forever. If you do this on a regular workstation or server with ECC RAM there is not issue (neither logical, technical nor physical)
  • Martin C.
    Martin C. almost 9 years
    Iterators often only have a notion of equality / inequality and not an ordering, that's why you use != for them. For instance, in a std::vector you could use < as the iterator is tied to the index / pointer, but in a std::set there is no such strict ordering, as it walks a binary tree.
  • Simon B
    Simon B almost 9 years
    There are some types, such as iterators, that don't support < or >, but do support == and !=.
  • Toby Speight
    Toby Speight almost 9 years
    You're quite right to emphasise the importance of idiom in programming. If I look at some code and it has a familiar pattern, I don't need to waste time inferring the pattern, but can go straight to the core of it. I guess that's my main grip with Yoda comparisons - they don't look idiomatic, so I end up having to read them twice to be sure they mean what I think they mean.
  • Mikkel Christiansen
    Mikkel Christiansen almost 9 years
    For readability i += step should be in the for control part. In the if you would step = 0
  • Zan Lynx
    Zan Lynx almost 9 years
    Using anything besides != with iterators is quite dangerous, because sometimes the iterators can be less-than compared (it's a pointer for example) but the comparison is meaningless (it's a linked list).
  • kfsone
    kfsone almost 9 years
    While that would help readability of good code, I wanted to emphasize the flaw in the erroneous version
  • Taekahn
    Taekahn almost 9 years
    Iterators are a perfect example of @AdrianMcCarthy point I think. The recommended comparison for them is != instead of <.
  • Num Lock
    Num Lock almost 9 years
    I like the intuition given in this answer. However, it doesn't really focus the question itself. (technical reasons vs. conventions)
  • Ely
    Ely almost 9 years
    It's a for loop with int. No iterators.
  • Jonathan Leffler
    Jonathan Leffler almost 9 years
    The second bullet is at best a frivolous reason. The code should be correct and clear. Compact is far less important.
  • msouth
    msouth almost 9 years
    Came in expecting this to be the highest voted answer; I was surprised I had to scroll this far to find it. This does a lot more toward convincing a novice programmer than "well, you should use the strongest condition". The other answers, if they stay on top, should incorporate this as a clear and obvious explanation of what can go wrong with OP's proposed code.
  • johan d
    johan d almost 9 years
    @msouth I fully agree, but my POV is quite subjective ;)
  • msouth
    msouth almost 9 years
    @johand. there is a question like this on, I think maybe a java thread ? somewhere, and one answer actually described it being a "pro" of the equality method--by getting stuck in an infinite loop, it will expose the bug of the iterator being incremented in the loop.
  • eggyal
    eggyal almost 9 years
    If the design of the loop should preclude the 6:30 pm from slipping by unnoticed then one should explicitly check that it has been seen/it is the time upon completion of the loop...
  • T.J. Crowder
    T.J. Crowder almost 9 years
    "But there is mitigation of risk, maintainability and better understanding of code." All of which are, properly, technical reasons. :-)
  • bishop
    bishop almost 9 years
    "I want this loop to run at most 5 times" vs. "I want to run this loop as many times as necessary, except exactly 5 times, which I don't want."
  • bishop
    bishop almost 9 years
    @JonathanLeffler Well, in a TDD REPL, that extra character is one extra nano-second for parsing, and times a billion iterations to find the bug caused by writing 5 != $i, that just took one whole second of my life. Uh... snicker
  • Jongware
    Jongware almost 9 years
    Not really endless - on most implementations of C, i will silently wrap around when at its maximum. But yeah, most likely longer than you are prepared to wait.
  • Jongware
    Jongware almost 9 years
    Ausgezeichnet. Similarly, one would not write the test as i < 17+(36/-3) (even when these are constants used elsewhere; then you must write out their names for clarity!).
  • faridSam
    faridSam almost 9 years
    I've seen exactly this error (and it caused 3 months of debugging) - but this answer entirely misses the point. In the given example it is impossible for the end condition to be missed. You could even say that to consciously choose != over < is to make a strong assertion of this fact. Mitigating a risk that definitively doesn't exist is a code smell to me. (Having said that, you can equally argue that < is idiomatic, that that is as good a reason to use it as any.)
  • deworde
    deworde almost 9 years
    @msouth I love it when unexpected production behaviour exposes my bugs, don't you? :-)
  • msouth
    msouth almost 9 years
    @deworde Yes! Yes, that's the best place to find them, because it really gives you a sense of urgency about fixing it when you take down a large client's operations. BTW, Here's the pro/con answer I was referring to (the question is referenced above): stackoverflow.com/questions/1783822/format-of-for-loops/… Also, the same argument is being made in comments on one of the answers above. Shaking my poor, jaded head.
  • Kickstart
    Kickstart almost 9 years
    If someone updates the loop counter within the for loop then it could skip the value 5
  • element11
    element11 almost 9 years
    +1 for mentioning the upper bound on a range. I think this is important for numerical ranges. != does not define a proper range in a for loop like these
  • Brilliand
    Brilliand almost 9 years
    @T.J.Crowder What type of reason is it when you just want to talk about what the machines will do as a result?
  • njzk2
    njzk2 almost 9 years
    one could argument that the infinite loop would be a good indicator of the mistake, but then another one would argue that i=5 is not necessarily a mistake
  • Miles Rout
    Miles Rout almost 9 years
    Learn to use white space, seriously.
  • deworde
    deworde almost 9 years
    @msouth Look, all we have to do is never make any mistakes ever and everything will be fine. Simples.
  • msouth
    msouth almost 9 years
    @deworde Ah! You mean write it without the bugs! I should start doing that. Seems like such an obvious idea, but sometimes it just takes that special kind of genius to point out what everyone is missing. I'm aware of the possible shock to the economy of entire QA departments suddenly becoming unemployed, so I'll roll this out slowly.
  • Brilliand
    Brilliand almost 9 years
    @DanSheppard I would generally consider mitigation of risk and maintainability to be business reasons, and better understanding of code to be a social reason (although those reasons are all being applied to a technical matter in this case). "Mitigation of risk" considerations aren't in any way limited to technical matters, and "better understanding of code" considerations can change if you find yourself working with a different group of people (even if the machines involved don't change at all).
  • Miles Rout
    Miles Rout almost 9 years
    for (int i=a;i<b;i++){} vs. for (int i = a; i < b; i++);
  • Paul Ogilvie
    Paul Ogilvie almost 9 years
    @ian-goldby, "...In the given example it is *impossible* for the end condition to be missed": that depends on how long work() takes...
  • Antonio
    Antonio almost 9 years
    @PaulOgilvie I think Ian Goldby referred to the example given in the question, not in my answer.
  • Miles Rout
    Miles Rout almost 9 years
    Learn to write readable code, and others won't need to learn to read it.
  • Carlton
    Carlton almost 9 years
    This is where I would use an assert or exception. If time should always be less than 6:30 prior to entering the loop, then the loop should be preceded by assert(time < 6:30) or some other kind of check.
  • Antonio
    Antonio almost 9 years
    @Carlton, time could become more than 6:30 within the loop, depending on what exactly happens within the Work() function
  • Miles Rout
    Miles Rout almost 9 years
    Without giving any other reason than that it is objectively poor style.
  • Josh Sanford
    Josh Sanford over 7 years
    One good example in support of this: Memory is vulnerable to bit flips (SEUs) caused by radiation. When using an int for an i != 15 condition, the counter will be running for a long time if anything above the fourth bit is flipped, especially on machines where sizeof(int) is 64. SEUs are a very real concern at higher altitude or in space (because of higher radiation), or in large supercomputers (because so much memory is present).
  • Luis Colorado
    Luis Colorado over 7 years
    Thinking that your program will run ok when radiation is changing your memory is an optimistic way and anticatastrophic way of thinking... good comment! :)
  • Lundin
    Lundin over 6 years
    If your loop iterator is a floating point number, then the != versus < is the least of your problems.
  • 463035818_is_not_a_number
    463035818_is_not_a_number over 5 years
    @MilesRout sorry for being stubborn. maybe time to remove some spam comments. cheers ;)
  • Yakk - Adam Nevraumont
    Yakk - Adam Nevraumont over 4 years
    @iang no, not if there is code in the body that edits i. It could be passed by const& to some function, that then static casts it back to editable and increments it an extra time (for whatever excuse; some programmer gettinf fancy and making an off by 1 error is dirt common). To prove it impossible you need to audit all uses of the loop variable for insanity.