Trying too hard?

J2SE 5.0 includes a new for-each loop that works like its C# or Visual Basic counterpart. It provides a simple, consistent idiom for iterating across collections or arrays. The for-each loop is intended to replace the need for working with Iterator or Enumeration objects or for using classic for loops to iterate across a collection.

For example, you can code:

int[] list = { 1, 2, 3 };

for (int i: list)
   System.out.println(i);

or:

List list = new ArrayList();
list.add(1);
list.add(2);
list.add(3);

for (int i: list)
   System.out.println(i);

Both produce the same, expected output. The syntax is reasonably obvious. The cooler part is that you can create your own iterable classes, simply by implementing the new Java interface java.lang.Iterable.

Sometimes I like being an object weenie. Having done enough Smalltalk, I prefer an object-based solution over a procedural solution most of the time. Uninformed claims to the contrary, a pure object-based solution can be elegant, powerful, and easily maintainable. Certainly procedural and other paradigms have their place, but you wouldn’t throw OO concepts into a C program, so why clutter an OO program with C code?

So, what about replacing classic C-style for loops with an OO concept? The basic idea is that instead of coding something like:

for (int i = 0; i < 10; i++)
   ...

you code:

for (int i: new Sequence(0, 9))
   ...

Here is the Sequence class. Tests follow.

import java.util.Iterator;

public class Sequence implements Iterable {
   private int start;
   private int stop;
   private int increment = 1;

   public Sequence(int start, int stop) {
      this.start = start;
      this.stop = stop;
   }

   public Sequence(int start, int stop, int increment) {
      this(start, stop);
      this.increment = increment;
   }

   public Iterator iterator() {
      return new SequenceIterator();
   }

   private class SequenceIterator implements Iterator {
      private int count = start;
      public boolean hasNext() {
         return count <= stop;
      }
   
      public Integer next() {
         int result = count;
         count += increment;
         return result;
      }
      
      public void remove() {
         throw new UnsupportedOperationException();
      }
   }
}

SequenceTest:

import junit.framework.*;
import java.util.*;

public class SequenceTest extends TestCase {
   private List ints;
   
   protected void setUp() {
      ints = new ArrayList();
   }

   public void testSingleEntry() {
      verifySequence(new Sequence(0, 0), 0);
   }

   public void testTwoEntries() {
      verifySequence(new Sequence(1, 2), 1, 2);
   }
   
   public void testMultipleEntries() {
      verifySequence(new Sequence(5, 10), 5, 6, 7, 8, 9, 10);
   }

   public void testNegativeNumbers() {
      verifySequence(new Sequence(-2, 2), -2, -1, 0, 1, 2);
   }
   
   public void testIncrement() {
      verifySequence(new Sequence(0, 5, 2), 0, 2, 4);
   }

   public void testIncrementIncludesLimit() {
      verifySequence(new Sequence(0, 6, 2), 0, 2, 4, 6);
   }

   private void verifySequence(Sequence sequence, int... expectedValues) {
      for (int i: sequence)
         ints.add(i);
      assertEquals(expectedValues.length, ints.size());
      for (int i: expectedValues)
         assertTrue(ints.contains(i));
   }
}

Sometimes things like this seem like a really dumb idea. It has a few potential values beyond my object compulsiveness: you can pass the Sequence around easily; you could persist it if you had to. You could also extend its complexity without having to alter code that uses a sequence.

Not very earth-shattering, and perhaps I’m trying too hard to create something where it’s not needed. But let me know if you find this useful.

 

Comments:

Not at all overkill. In fact, as a means to really get my head around J2SE 5 (especially generics), I’ve been working on a collections library influenced by the ANSI Smalltalk collection protocols: http://sf.net/projects/jaggregate. I know this treads over “Essential Java Style” territory, but it’s been educational, and who knows, maybe it’ll catch on at some point. I’m writing benchmarks for ArrayList vs. OrderedCollection right now…will also pit HashSet vs. Set, HashMap vs. Dictionary, etc.

The closer we get to “everything is an object”, the better IMHO.

Atom