tags:

views:

313

answers:

9

What's the best/preferred idiom for a decrementing for loop, and why?

for(int idx=(len-1); idx>=0; idx--) {...}

or

for(int idx=(len-1); idx>-1; idx--) {...}

or (based on sylvarking's answer, but using for to constrain the index scope)

for(int idx=len; idx-->0; ) {...}

Is one or the other more likely to trip up another developer?

A: 

First one; it's the standard way.

Noon Silk
+1  A: 

I can't say I've ever seen the latter, so here's one vote for the first one.

There should be no performance difference.

Note your loops iterate over max+1 elements. Normally I suppose I'd expect iteration from max-1 down to 0.

Sean Owen
Oops; good point - I was just working on some code that was inclusive (was actually from top to bottom of a rectangular area).
Software Monkey
See, much too easy to mess up :) Keep to the standard 0..MAX - 1 idiom.
Thorbjørn Ravn Andersen
@Thorbjorn: Actually, I believe that this is the first time in 30 years of programming I have made this mistake, and this quite likely because I was actually working on a (different) inclusive loop when I asked the question because I saw a decrementing loop nearby in the code.
Software Monkey
+1  A: 

Interesting question! Personally, I use the first and it is the one I see used most by other programmers. I think the reason is that people are used to testing for zero and the -1 might throw them a bit.

Michael Bobick
+10  A: 

Another array-oriented variant you might see is this:

int n = foo.length;
while (n-- > 0) {
  /* Do something with foo[n] */
}

Of the options you show, I prefer the first.

  • 0 is (arguably) more readable than -1.
  • Comparison to zero is usually faster than comparison to other constants. It is a single instruction that examines a single value on the stack. Other comparisons use one instruction to push a constant onto the stack and another instruction to compare the top two values.
erickson
I prefer this version too, though typically I'd go for `for (int i= a.length; i-->0;)` idiom if it was a trivial reverse-iterator that didn't do anything clever with the loop variable or have an extra `break` in there.
bobince
But taking advantage of the comparison to zero opcode, one would need idx!=0 - something I avoid on principle because loops can then overrun if the index is irregularly changed (decremented or incremented by more than 1, possibly only under some conditions).
Software Monkey
No, written as I've shown, a decent compiler will use the `ifgt` opcode; there's a zero-based opcode for each relation: `ifeq`, `ifne`, `iflt`, `ifle`, `ifgt`, `ifge`.
erickson
P.S., I agree about using `>` rather than `!=`. Just in case.
erickson
`n --> 0` just looks sooo much cleaner, though!
LiraNuna
One thing I *don't* like about this is that the scope of n is greater than the loop; using for(int n... constrains the scope better.
Software Monkey
Yes, that's true. Minimizing the scope is actually better, technically, but the empty clause looks a bit ugly to me.
erickson
A: 

The second is still confusing me.
The first is (more or less) what one is expecting, in a decrementing for loop, one does not have to check for >-1 just not to have the equals.

Personally I would've done as Mark Byers wrote.

Alberto Zaccagni
+1  A: 

I recommend the following because comparison against zero is optimized at the byte code level.

for(int idx=(len-1); idx>=0; idx--) {...}

This is a suggestion from Java Performance Tuning by Jack Shirazi

Matthew Sowders
Byte codes are further processed, and you cannot predict actual running time without knowing what code will be executed at end. I believe HotSpot is very well equipped to optimize the int i = 0; i < MAX; i++ case.
Thorbjørn Ravn Andersen
That is true Thorbjørn. Shirazi notes in Java Performance Tuning that the latest VMs optimize standard for(int idx=0;idx<max;i++) so writing it this way may have no additional affect. Thanks for pointing that out. However, it does not hurt.
Matthew Sowders
A: 

i have found that for-loops with a counter should only go from zero and up to some limit.

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

This is so well established that you can expect that anybody who sees this immediately understand what is going on. This also means that any DEVIATION from that form, by counting backwards or starting at one or stepping by three, makes it hard to understand because you need to recognize it is dfifferent, parse it and understand it. This includes all your examples.

I would suggest writing it clearly:

for(int i = 0; i < MAX; i++) {
  indexFromEnd = (MAX - 1) - i;
....
 }
Thorbjørn Ravn Andersen
I don't agree with this. I think yur refactored example also makes it hard to understand because I have to stop and think what your indexFromEnd line is doing. A decrementing for loop is hardly difficult to understand as the -- instead of ++ will be an immediate visual clue.
Then give it a better name. The context given is insufficient to do so. I still maintain my stance that for loops should be simply 0..MAX-1
Thorbjørn Ravn Andersen
I also have to disagree; to me, coding an incrementing loop in this context fails to express the intent of the loop. If I am searching an array backwards to find the last match, then a decrementing loop expresses that better (again, to me). Your example seems counter-intuitive in any real context.
Software Monkey
A: 

If you have a list use a ListIterator:

Following example based on http://www.java-samples.com/showtutorial.php?tutorialid=235

class ListIter {
    public static void main(String args[]) {
     // create an array list
     ArrayList al = new ArrayList();
     // add elements to the array list
     al.add("A");
     al.add("B");
     al.add("C");
     al.add("D");
     al.add("E");
     al.add("F");
     // use ListIterator to display contents of al backwards
     ListIterator litr = al.listIterator(al.size());
     while (litr.hasPrevious()) {

      Object element = litr.previous();
      System.out.print(element + " ");

     }
     System.out.println();
    }
}
crowne
A: 

My vote is for:

for(int idx=(len-1); idx>=0; idx--)

And as an aside, I favor the prefix increment/decrement operator (--idx) in for for-loops, since it will avoid taking an unnecessary copy of idx (though many compilers will probably recognize this and fix it for you).

Setien