When reviewing, I sometimes encounter this kind of loop:
i = begin
while ( i != end ) {
// ... do stuff
if ( i == end-1 (the one-but-last element)
Its just about using it as per need and convenience. There is as such no mentions to treat elements equally and there is certainly no harm clubbing the features which language provides.
Of course, special-casing things in a loop which can be pulled out is silly. I wouldn't duplicate the do_stuff either though; I'd either put it in a function or a macro so I don't copy-paste code.
I know I've seen this when people tried to join elements of an array into a comma-seperated string:
for(i=0;i<elements.size;i++) {
if (i>0) {
string += ','
}
string += elements[i]
}
You either have that if clause in there, or you have to duplicate the string += line again at the end.
The obvious solution in this case is
string = elements.join(',')
But the join method does the same loop internally. And there isn't always a method to do what you want.
I don't think this question should be answered by a principle (e.g. "in a loop, treat every element equally"). Instead, you can look at two factors to evaluate if an implementation is good or bad:
If it is faster and the code is more readable by doing everything in one loop, do it that way. If it is slower and less readable, do it another way.
If it is faster and less readably, or slower but more readable, find out which of the factors matters more in your specific case, and then decide how to loop (or not to loop).
I came to a realization that when I put special cases in a for loop, I'm usually being too clever for my own good.
I think you are right about the loop being meant to deal with all elements equally. Unfortunately sometimes there are special cases though and these should be dealt with inside the loop construct via if statements.
If there are lots of special cases though you should probably think about coming up with some way to deal with the two different sets of elements in separate constructs.