views:

750

answers:

13
+11  Q: 

format of for loops

Hi, i'd just like to get some thoughts on the best way to do for loops (in c based languages). all over the web code samples have for loops which look like this

for(int i = 0; i < 5; i++)

while i used the following format

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

i do this because i believe it to be more efficent but does this really matter in most cases.

your thoughts on the matter would be great

+28  A: 

If for some reason i jumps to 50 in the loop, your version would loop forever. The i < 5 is a sanity check.

Yuriy Faktorovich
If i is being modified in the loop, things are bad enough that I'd probably _rather_ have an infinite loop to help me track down what's going on. Seriously, if something is messing with i, there should be an assert in the loop to find out. Another reason I prefer languages that let me do a foreach instead of a for whenever possible.
Nosredna
Is it really that bad? What if someone wants to break out of the loop after its finished? Setting i to int.MaxValue would do the trick without refactoring.
Yuriy Faktorovich
Setting i to break out of the loop? Ugh. If _break_ doesn't work to do that, refactor!
Nosredna
@Yuriy Faktorovich: So would `break;`
Will Eddins
what about a normal break instead of setting the iterator to int.MaxValue?
PoweRoy
Thats my point, what if it figures out that it needs to exit in some business logic at the beginning of the clause. break; wouldn't execute the remaining logic.
Yuriy Faktorovich
Although at that point, Nosredna is likely right, refactoring may be in order.
Yuriy Faktorovich
Except that C, C#, and C++ all have `break;`.
David Thornley
@Yuriy. For that case, adding a boolean flag would be clearer than altering i.
Nosredna
break; won't work properly in a nested loop, will it? : `for (int i = 0; i < 10; ++i) { for (int j = 0; j < 10; ++j) { if (someCondition) { i = 10; break; /* how else can I break out of the outer loop here? */ } }`
Bill
@Bill you gotta use goto statements(It is great to say "using goto is the right way", very rarely do I get that ability).
Yuriy Faktorovich
The `<` version over the `!=` can make it easier to write loop invariants for proving correctness.
caf
+1  A: 

Well... that's fine as long as you don't modify i inside your for loop. The real "BEST" syntax for this entirely depends on your desired result.

md5sum
+6  A: 

If the increment rule changes slightly you immediately have an infinite loop. I much prefer the first end condition.

Chris Ballance
True. Going to i+=2 in the example leads to pain.
Nosredna
+16  A: 

The form

for (int i = 0; i < 5; i++)

is idiomatic, so it's easier to read for experienced C programmers. Especially when used to iterate over an array. You should write idiomatic code whenever possible as it reads faster.

It is also a little safer in situations when you modify i inside the loop or use an increment different then 1. But it's a minor thing. It's best to carefully design your loop and add some asserts to catch broken assumptions early.

Tomek Szpakowicz
This is a very good point!
Skilldrick
+3  A: 

The second is less readable, I think (if only because the "standard" practice seems to be the former).

MoominTroll
+5  A: 

C++ texts often suggest the second as that format will work with iterators which can be compared (!=) directly but not with a greater to or less than condition. Also pre increment can be faster than post increment as there is no need for a copy of the variable for comparison - however optimisers can deal with this.

For integers etc either form works for C the first is the common idiom for C++ the second

For C# and Java use I would foreach to loop over all things.

In C++ there is also the std::for_each function requiring a use of a functor which for simple cases is probably more complex than either example here and the Boost FOR_EACH which can look like the C# foreach but is complex inside.

Mark
Qt also has Q_FOREACH to solve the same problem, btw.
Marcus Lindblom
Good point about C++. +1
jalf
+2  A: 

With regards to using ++i instead of i++, it doesn't make a difference with most compilers, however ++i could be more effiecient that i++ when used as an iterator.

Calum
+1  A: 

I would never do this:

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

i != 5 leaves it open for the possibility that i will never be 5. It's too easy to skip over it and run into either an infinite loop or an array accessor error.

++i

Although a lot of people know that you can put ++ in front, there are a lot of people who don't. Code needs to be readable to people, and although it could be a micro optimization to make the code go faster, it really isn't worth the extra headache when someone has to modify the code and figure why it was done.

I think Douglas Crockford has the best suggestion and that is to not use ++ or -- at all. It can just become too confusing (may be not in a loop but definitely other places) at times and it is just as easy to write i = i + 1. He thinks it's just a bad habit to get out of, and I kind of agree after seeing some atrocious "optimized" code.

I think what crockford is getting at is with those operators you can get people writing things like:

var x = 0;
var y = x++;

y = ++x * (Math.pow(++y, 2) * 3) * ++x;

alert(x * y);

//the answer is 54 btw.

Kevin
i feel that appropriate comments in the code make it a lot easier to read than the syntax but that said a lot of people will still look at it and be confused as why it has been done this way
harryovers
I can't disagree with you more. I expect that knowing prefix vs postfix increment is among the absolute minimum of knowledge that I would accept for a maintenance programmer. I think it should be used when it can be, because it's very easy to mistype i = i + 1 in a way that the compiler won't catch.
rmeador
@rmeador don't get me wrong, I totally agree with you that they should know it. My problem is that I can't code for what I think should be, I have to code for what is. I will say there are other times too where trying to be terse leads to possible assumptions that aren't correct. Mostly these are stupid things that taking up 2 lines instead of 1 would have become evident. Little stupid mistakes that could have been avoided.
Kevin
If people don't understand ++i, they have no business writing code.
jalf
@jalf whether or not you think that is true, there are people who still get tripped up by that.
Kevin
Your advice doesn't apply well to C++, because there are situations in C++ when you very definitely want `for (i = ...; i != ...; ++i)`, if `i` is not a random-access iterator and/or `i` is fairly complicated. It's useful to develop good habits rather than miss something and code something improperly.
David Thornley
I assumed people learned pre- and post-incrementing at the same time. But maybe not. Post-incrementing is much more common, so I suppose someone who learns by reading code may be familiar with one and not the other. By the way, Crockford's probably right for the cases where pre- and post-incrementing are used in a complex expression. Personally, I turn that pickiness off in jsLint. i++ sitting all alone should not be confusing to anyone.
Nosredna
+33  A: 

Everybody loves their micro-optimizations, but this would not make a difference as far as I can see. I compiled the two variations with g++ on for intel processors without any fancy optimizations and the results are for

for(int i = 0; i < 5; i++):

    movl $0, -12(%ebp)
    jmp L2
L3:
    leal -12(%ebp), %eax
    incl (%eax)
L2:
    cmpl $4, -12(%ebp)
    jle L3

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

    movl $0, -12(%ebp)
    jmp L7
L8:
    leal -12(%ebp), %eax
    incl (%eax)
L7:
    cmpl $5, -12(%ebp)
    jne L8

I think "jle" and "jne" should translate to equally fast instructions on most architectures. So for performance you should not distinguish between the two. In general I would agree that the first one is a little safer and I also think more common.

Lucas
good effort! i think i will still use my way though
harryovers
+1 for due diligence
Chris Ballance
@harryovers: I have to say, that I wouldn't be confused by your way. I think it is pretty obvious what is going on, but you shouldn't get to worked up about small optimizations, if you don't have a performance issue.
Lucas
i'm not really worried about it i just wanted to know what thoughts people had
harryovers
@Chris: I had to look up diligence. I am adding a word to my English vocabulary list every day. That just made the list.
Lucas
The important part of this is that x86 uses a condition code register, so it computes both equality and sign flags for any comparison, so conditional jumps for all integral in/equalities take exactly the same amount of time.
Ken
@Lucas: Aside from the meaning of "diligence" on its own, "due diligence" is the term for what you do when you're thinking of buying a company ("you" being another company, usually, but it can also apply when brokers offer shares for sale). Checking their accounts, making sure their major assets really exist, and so on, to establish that the proposed price is reasonable and the company won't turn into leaves the morning after you buy it...
Steve Jessop
A: 

If your index were not an int, but instead (say) a C++ class, then it would be possible for the second example to be more efficient.

However, as written, your belief that the second form is more efficient is simply incorrect. Any decent compiler will have excellent codegen idioms for a simple for loop, and will produce high-quality code for either example. More to the point:

  • In a for loop that's doing heavy performance-critical computation, the index arithmetic will be a nearly negligible portion of the overall load.

  • If your for loop is performance-critical and not doing heavy computation such that the index arithmetic actually matters, you should almost certainly be restructuring your code to do more work in each pass of the loop.

Stephen Canon
If the index wasn't a random-access iterator (in C++), the first version wouldn't even be correct.
David Thornley
+1  A: 

Numeric literals sprinkled in your code? For shame...

Getting back on track, Donald Knuth once said

We should forget about small efficiencies, say about 97% of the time: premature optimization is the root of all evil.

So, it really boils down to which is easier to parse

So... taking into account both of the above, which of the following is easier for a programmer to parse?

for (int i = 0; i < myArray.Length; ++i)

for (int i = 0; i != myArray.Length; ++i)

Edit: I'm aware that arrays in C# implement the System.Collections.IList interface, but that's not necessarily true in other languages.

R. Bemrose
Why would you iterate one time less in the second example?
UncleBens
i wouldn't do "i != myArray.Length - 1". i'd prefer "i = 0, n = myArray.Length; i != n"
harryovers
Good answer. Of course, we don't know that he's going through an entire array. In fact, with that numeric literal in there we have no idea what he's doing.
Nosredna
This is a case where counting down can be faster, depending how fast getting the length of an array is.
Nosredna
@UncleBens: You wouldn't. Braino on my part.
R. Bemrose
@Nosredna, why can't a compiler optimize out finding the length of the array? Most compilers can figure out if the length of the array can change within the loop.
tster
+1  A: 

Regarding readability. Being a C# programmer who likes Ruby, I recently wrote an extension method for int which allows the following syntax (as in Ruby):

4.Times(x => MyAction(x));
Martin R-L
+1  A: 

In generic code you should prefer the version with != operator since it only requires your i to be equally-comparable, while the < version requires it to be relationally-comparable. The latter is a stronger requirement than the former. You should generally prefer to avoid stronger requrements when a weaker requirement is perfectly sufficient.

Having said that, in your specific case if int i both will work equally well and there won't be any difference in performance.

AndreyT