27 December 2008

For-each loop: Small language changes on JDK 7

Lets talk about:

  • For-each loop over a Map
  • Control over for-each loops (index/remove)

At first, I asked myself if it's possible to obtain those targets just by a simple code.?
It's not so clear for all, but answer is YES.
However, there are still some small languages changes that would improve programming quality.

Indexing control over for-each loops

What would be the effect of adding indexing directly to for-each loop?

  • Language syntax need to be extended.
  • While loop can iterate more than MAX_INT there might be possibility to obtain exception (IndexOutOfBoundsException)
  • We will not be able to obtain some more complicated indexes (like even numbers, numbers started from 333, ...)
  • It's higher probability that when people get used to it they will want a more complicated syntax

What is the impact of other solutions?

  • Implement IntIterator, LongIterator
  • Possible to extend for-each loop with increment (initialization) expression for (String s:array; intIterator.next()) { ... }
  • We would be able to index everything
  • No negative impact during extending loop statement
  • We could selectively index elements

Sample:

/*
 * @author Marek Kozieł
 */

public interface IntIterator extends Serializable {

  /*
   * Returns <tt>true</tt> if the iteration has more elements. (In other words, returns <tt>true</tt> if <tt>next</tt> would return an element rather than throwing an exception.)
   *
   * @return <tt>true</tt> if the iterator has more elements.
   */

  public boolean hasNext();

  /*
   * Returns the next element in the iteration.
   *
   * @return the next element in the iteration.
   * @exception NoSuchElementException iteration has no more elements.
   */

  public int next();

  public static class IntIteratorImpl implements IntIterator {

    public IntIteratorImpl() {
      last = 0 - 1;
    }

    public IntIteratorImpl(int starValue) {
      if (starValue == Integer.MIN_VALUE) { throw new IllegalArgumentException("Start value(" + starValue + ") is unsupported"); }
      last = starValue - 1;
    }

    private int  last  = 0;

    @Override
    public final boolean hasNext() {
      return (last != Integer.MAX_VALUE);
    }

    @Override
    public final int next() {
      if (last == Integer.MAX_VALUE) { throw new NoSuchElementException(); }
      return (last++);
    }

  }

}

Removing control over for-each loops

What would be the effect of adding indexing directly to for-each loop?

  • Possible, but for loop should know if it's iterate through Iterator.
  • Syntax need to be extended like:
    for.remove(...).

What is the impact of another solutions?
Allow for-each loop to iterate through Iterator not only through Iterable!

  • Will allow use more complicated Iterators!
  • Container would be able to return easily few iterators (Map iterator over: keys, values, distinct values, keys & values ) without complicated objects structure.
  • No syntax change is required!

For-each loop over a Map

What would be the effect of allowing loop to work on Map-s?

  • Language would become dependent from Map implementation
  • Syntax need to be extended!

What is the impact of another solution?
I personally use solution that allow me to iterate through my own Map-s for a few months. Container is just able to return a few different iterators (see previous solution).

Summary

  • Language changes can have high negative impact.
  • Making language dependent from one implementation will skip people from implemending better ones.

Another sugestion: Allow for-each loop iterator through more than one container

Effect:

  • Syntax need to be extended:
    for(String s: array,collection,iterator)
    if (for.current==array) { ... }
  • Skipping people from writing a few loops with the same content!

4 comments:

  1. For-each loop over a Map
    You already have this in Java:
    for(Map.Entry e : map.entrySet()) {
    // do something with e.getKey() and e.getValue()
    }

    Indexing control over for-each loops
    Why do you need this indexing? Perhaps to copy data between array and collection. So better instead of array, use ArrayList.

    Removing control over for-each loops
    Yes, this can be disappointing. I had for(E e : collection), then I noticed that I need removal there. Do I need to change it to for(Iterator<E> it = collection.iterator(); it.hasNext(); ){E e = it.next .... Code is much less readable. But this can be easily done without any language extensions:
    IterableHelper<E> helper = IterableHelper.create(collection);
    for(E e : helper) {
    ...
    helper.remove();
    ...
    }

    Another sugestion: Allow for-each loop iterator through more than one container
    I can't remember if I ever needed it in my programming experience - no need to add it to Java if it's almost never used. But you can create a special method for this:
    interface F<E> { void f(E e){} }
    ...
    Utils.forEach(new F<E>() {
    void f(E e) {
    ...
    }
    }, collection1, collection2, ...);
    A lot more typing, but it's not a problem. As I wrote, it happens very rarely. This way you can do other tasks that would otherwise require duplicating of your code.

    ReplyDelete
  2. >For-each loop over a Map
    Personally, I do not use maps at all, but maybe people do not know this solution.

    >Why do you need this indexing?
    I've already said that I'm against of indexing in loop.

    ReplyDelete
  3. Almost all developers know about Map.entrySet() and use it to iterate map.

    ReplyDelete
  4. >Almost all developers know about Map.entrySet() and use it to iterate map.

    It's not about possibility, I just do not like the logics according to which it's done like that.

    ReplyDelete