Is there a technical reason to use > (<) instead of != when incrementing by 1 in a 'for' loop?
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).
Related videos on Youtube
Zingam
Updated on July 14, 2022Comments
-
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 afor
loop? Or this is more of a convention?-
barak manos almost 9 yearsIt makes it more readable, plus, if you ever change
i++
toi+=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 almost 9 years
5 != i
is evil -
Werner Henze almost 9 yearsNo technical reason. Just a question of style/preference.
-
alk almost 9 years... and robustness of the code. @WernerHenze
-
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 almost 9 yearsI agree with Zingam regarding the later change and being conscious of your actions, but I think @barakmanos makes a valid point.
-
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 almost 9 yearsYou 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 almost 9 yearsYour 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 almost 9 years@OleTange If you are iterating using floating point numbers you are already screwed..
-
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 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 ) ...
andif ( i = 5 )
. Very different things. Reversing the operands prevents the problem: since literals are notlvals
, they can't be assigned to and the compiler hurls on the typo. @Zingam: good defensive programming! -
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 almost 9 yearsAs 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 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 almost 9 years@NicholasCarey I have personally always been saved by a compiler warning in those cases.
-
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 almost 9 yearsMany 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 almost 9 years@Slava - what is evil about
5 == i
? -
Slava almost 9 years@ToniLeigh in short:
5.operator==( i )
fails. It is even worse ifi
has implicit conversion operator. -
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 to5 == i
? -
Slava almost 9 years@ToniLeigh if
i
is an instance of class that hasoperator==(int)
then statementi == 5
would compile, but5 == i
would fail. Ifi
hasoperator double()
then5.0 == i
would produce difficult to catch bug. -
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 typoi = 5
-
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 because5 > i
would be even worse, so he wants to keep constant on the left and that implies!=
instead of < or > -
eversor almost 9 years
5 != i
that a yoda condition is -
Gianluca Ghettini almost 9 yearsyes.. 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 over 8 yearsYoda 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 over 8 yearsI'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 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 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 over 8 yearsUnfortunately, the "duplicate" question also conflates a second issue (pre- v. post-increment) and focuses on the efficiency of that.
-
Lundin over 6 yearsThe 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 over 5 yearsRe floats: on all sensible implementations, floats represent integers exactly until you overflow the range of mantissa. On most platforms where
sizeof(double) > sizeof(int)
, adouble
can hold integers larger than what fits into anint
.
-
-
Ely almost 9 yearsNice example. I'd be interested in a case for
!=
instead of<
. I personally never used that I think. -
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 almost 9 yearsyou 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 almost 9 yearsThe 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 almost 9 yearsThis type of inner "if (condition) then i++" is the first thing I thought of.
-
Adrian McCarthy almost 9 yearsSometimes, 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 almost 9 years@AdrianMcCarthy: Not necessarily; it could just introduce a second bug, making diagnosis harder.
-
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 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 almost 9 yearsThe logic is perfectly fine. When
i
is5
the loop exits. Did you mean to say something else? -
emory almost 9 yearsThis 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 almost 9 yearsIf 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. almost 9 yearsIterators often only have a notion of equality / inequality and not an ordering, that's why you use
!=
for them. For instance, in astd::vector
you could use<
as the iterator is tied to the index / pointer, but in astd::set
there is no such strict ordering, as it walks a binary tree. -
Simon B almost 9 yearsThere are some types, such as iterators, that don't support < or >, but do support == and !=.
-
Toby Speight almost 9 yearsYou'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 almost 9 yearsFor readability i += step should be in the for control part. In the if you would step = 0
-
Zan Lynx almost 9 yearsUsing 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 almost 9 yearsWhile that would help readability of good code, I wanted to emphasize the flaw in the erroneous version
-
Taekahn almost 9 yearsIterators are a perfect example of @AdrianMcCarthy point I think. The recommended comparison for them is != instead of <.
-
Num Lock almost 9 yearsI like the intuition given in this answer. However, it doesn't really focus the question itself. (technical reasons vs. conventions)
-
Ely almost 9 yearsIt's a for loop with int. No iterators.
-
Jonathan Leffler almost 9 yearsThe second bullet is at best a frivolous reason. The code should be correct and clear. Compact is far less important.
-
msouth almost 9 yearsCame 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 almost 9 years@msouth I fully agree, but my POV is quite subjective ;)
-
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 almost 9 yearsIf 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 almost 9 years"But there is mitigation of risk, maintainability and better understanding of code." All of which are, properly, technical reasons. :-)
-
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 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 almost 9 yearsNot 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 almost 9 yearsAusgezeichnet. 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 almost 9 yearsI'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 almost 9 years@msouth I love it when unexpected production behaviour exposes my bugs, don't you? :-)
-
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 almost 9 yearsIf someone updates the loop counter within the for loop then it could skip the value 5
-
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 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 almost 9 yearsone 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 almost 9 yearsLearn to use white space, seriously.
-
deworde almost 9 years@msouth Look, all we have to do is never make any mistakes ever and everything will be fine. Simples.
-
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 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 almost 9 years
for (int i=a;i<b;i++){}
vs.for (int i = a; i < b; i++);
-
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 almost 9 years@PaulOgilvie I think Ian Goldby referred to the example given in the question, not in my answer.
-
Miles Rout almost 9 yearsLearn to write readable code, and others won't need to learn to read it.
-
Carlton almost 9 yearsThis 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 byassert(time < 6:30)
or some other kind of check. -
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 almost 9 yearsWithout giving any other reason than that it is objectively poor style.
-
Josh Sanford over 7 yearsOne good example in support of this: Memory is vulnerable to bit flips (SEUs) caused by radiation. When using an
int
for ani != 15
condition, the counter will be running for a long time if anything above the fourth bit is flipped, especially on machines wheresizeof(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 over 7 yearsThinking that your program will run ok when radiation is changing your memory is an optimistic way and anticatastrophic way of thinking... good comment! :)
-
Lundin over 6 yearsIf your loop iterator is a floating point number, then the
!=
versus<
is the least of your problems. -
463035818_is_not_a_number over 5 years@MilesRout sorry for being stubborn. maybe time to remove some spam comments. cheers ;)
-
Yakk - Adam Nevraumont over 4 years@iang no, not if there is code in the body that edits
i
. It could be passed byconst&
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.