Improved for each loop

M

markspace

Just thinking out loud here, mostly. I seem to write a lot of the
following type of loop:

Object[] array ....
for( int i = 0; i < array.length; i++ ) {
....
}

That is, a sequence of numbers less than some bound, starting at zero.
Wouldn't a compact form of this be handy?

Object[] array ....
for( int i : array.length ) {
....
}

The difference between this and the regular for-each is that the
identifier after the colon isn't an object (not an Iterable or an array)
but an integer primitive. It should work even with literals:

for( int i : 42 ) {
.... // i == 0..41 inclusive
}

With Java 7 coming up, is this JSR worthy?
 
M

Mike Schilling

markspace said:
Just thinking out loud here, mostly. I seem to write a lot of the
following type of loop:

Object[] array ....
for( int i = 0; i < array.length; i++ ) {
....
}

What do you do with i, other than say

Object o = array;

?
 
M

markspace

Patricia said:
However, I'm not convinced there enough simplification between the
existing and proposed syntax to justify another for-loop variant.


It seems to be to be a reasonable extension to the existing syntax, but
I'm not 100% convinced either. I just almost wrote it by accident when
writing an array loop, and I wanted to explore the idea a little more.
But the idea does seem useful, since the particular series of numbers,
from 0 to an upper bound, is so often used.
 
L

Lew

markspace said:
It seems to be to be a reasonable extension to the existing syntax, but
I'm not 100% convinced either. I just almost wrote it by accident when
writing an array loop, and I wanted to explore the idea a little more.
But the idea does seem useful, since the particular series of numbers,
from 0 to an upper bound, is so often used.

The variant that my hands want to type is:

Collection <Foo> foos = obtainSomehow();
for ( int ix = 0; Foo foo : foos; ++ix )
{
sparse.put( ix, foo );
}

That said, I'm pretty content with the loops we have now.
 
R

Roedy Green

Object[] array ....
for( int i : array.length ) {
....
}

These in theory require an Iterable interface somewhere. Perhaps that
is why they left that off.

You might generalise that to also permit things like this:

for ( int i: anArray )

for ( int i: anArrayList )

for ( int i: someString )

I think those extensions are safe. If muddled them up with the
existing forms, the body of the loop would generate type errors.

I am all in favour of short forms for common idioms. You eye can
grasp them in an instant and be sure some tiny variant is not
masquerading as a common idiom the way is so often with the standard
for.

There was one oversight in the original that logically should have
been there.

for ( char c : string )

If it makes you feel any better, In my home brew language Abundance
circa 1980, You could abbreviate those to

<<<FOR anArray ... FOR>>>
<<<FOR anArrayList ... FOR>>>
--
Roedy Green Canadian Mind Products
http://mindprod.com

"For reason that have a lot to do with US Government bureaucracy, we settled on the one issue everyone could agree on, which was weapons of mass destruction."
~ Paul Wolfowitz 2003-06, explaining how the Bush administration sold the Iraq war to a gullible public.
 
M

markspace

Roedy said:
You might generalise that to also permit things like this:

for ( int i: anArray )

for ( int i: anArrayList )


Uh.... Roedy these are in the language now. They support widening and
auto-unboxing too.

byte[] test = { 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51 };
for( int i : test ){
System.out.println( i );
}
ArrayList<Integer> al = new ArrayList<Integer>();
al.add( 2 );
al.add( 1 );
for( int i : al ) {
System.out.println( i );
}

You might want to Google "java foreach", check the syntax on it, it's
been around since 2004.
 
D

Daniel Pitts

Roedy said:
Object[] array ....
for( int i : array.length ) {
....
}

These in theory require an Iterable interface somewhere. Perhaps that
is why they left that off.

You might generalise that to also permit things like this:

for ( int i: anArray )

for ( int i: anArrayList )

for ( int i: someString )

I think those extensions are safe. If muddled them up with the
existing forms, the body of the loop would generate type errors.
Not really:


int[] anArray;
for (int i: anArray) // Oops.

List<Integer> anArrayList;
for (int i: anArrayList) // oops.
 
M

markspace

Lew said:
The variant that my hands want to type is:

Collection <Foo> foos = obtainSomehow();
for ( int ix = 0; Foo foo : foos; ++ix )
{
sparse.put( ix, foo );
}

That's an interesting idea. I wonder if for-each could be expanded to
include an Iterator too.

for( Interator<> i -> foos ) {
if( i.next().equals( badValue ) ) {
i.remove();
}
}

But this appears to have been deliberately excluded by the language
designers.
That said, I'm pretty content with the loops we have now.

I can't make a strong case for including this feature. It's mostly a
convenience, and also the small probability that one will mess up the
current version of the counting loop. The counting loop is so common,
however, it seems like it might be useful to reduce even a small
probability. Especially writing test cases, I seem to do a LOT of
iteration over an array of test values.
 
J

Joshua Cranmer

markspace said:
The difference between this and the regular for-each is that the
identifier after the colon isn't an object (not an Iterable or an array)
but an integer primitive. It should work even with literals:

for( int i : 42 ) {
.... // i == 0..41 inclusive
}

The problem here is that the syntax is slightly ambiguous on read: does
i achieve the value of 42 or not?

If you really want this feature, it's possibly right now:

public final class IteratorUtils {
public static <T> Iterable<T> getIterable(final Iterator<T> it) {
return new Iterable<T>(){public Iterator<T> iterator(){return it;}};
}
public static Iterable<Integer> range(final int high) {
return getIterable(new Iterator<Integer>() {
private int i = 0;
public boolean hasNext() { return i == high; }
public Integer next() { return i++; }
public void remove() {}
});
}

public static void main(String... args) {
for (int i : range(42)) {
System.out.println(i);
}
}
}
With Java 7 coming up, is this JSR worthy?

I believe you're looking for Project Coin (a collection of small
language changes for JDK 7), but its ultimate acceptance would be
suspect: the ability to create one's own Iterable implementations means
that it's almost trivial to roll it out, and probably easier to
understand that way, too.
 
A

Arne Vajhøj

Roedy said:
Object[] array ....
for( int i : array.length ) {
....
}

These in theory require an Iterable interface somewhere. Perhaps that
is why they left that off.

Not with the sematics proposed.
You might generalise that to also permit things like this:

for ( int i: anArray )

for ( int i: anArrayList )

for ( int i: someString )

I think those extensions are safe. If muddled them up with the
existing forms, the body of the loop would generate type errors.
There was one oversight in the original that logically should have
been there.

for ( char c : string )

The first two work fine in Java (since 1.5).

For the last two to work you need to call .toCharArray(). No
big deal.

Arne
 
A

Arne Vajhøj

markspace said:
Just thinking out loud here, mostly. I seem to write a lot of the
following type of loop:

Object[] array ....
for( int i = 0; i < array.length; i++ ) {
....
}

That is, a sequence of numbers less than some bound, starting at zero.
Wouldn't a compact form of this be handy?

Object[] array ....
for( int i : array.length ) {
....
}

The difference between this and the regular for-each is that the
identifier after the colon isn't an object (not an Iterable or an array)
but an integer primitive. It should work even with literals:

for( int i : 42 ) {
.... // i == 0..41 inclusive
}

With Java 7 coming up, is this JSR worthy?

I don't think so.

Saving a little bit of typing is not worth changing the language for.

And the new construct does seem more readable than the old one.

A lot of people are used to 3 argument for loop - not just in Java
but in other languages.

Arne
 
M

markspace

Joshua said:
If you really want this feature, it's possibly right now:

public final class IteratorUtils {
public static <T> Iterable<T> getIterable(final Iterator<T> it) {
return new Iterable<T>(){public Iterator<T> iterator(){return it;}};
}
public static Iterable<Integer> range(final int high) {


This is a clever idea. I'll try this and see if it helps. BTW, I think
your test in hasNext() is incorrect. It should be !=, not ==, or maybe
<= or <, which will catch problems if the user calls next() too many
times and increments I over the bound.

My version is at the end of this post.
I believe you're looking for Project Coin (a collection of small


Thanks again, I'll take a look at that.

Code follows:

package local.itorutils;

import java.util.Iterator;


public class Iterators {

private Iterators() {}

/**
* Returns an Iterable that counts from 0 up to, but not including, the
* bound.
* @param bound Upper bound, exclusive, for this Iterable.
* @return An Iterable which counts 0..bound-1 inclusive.
*/
public static Iterable<Integer> rangeX( final int bound ) {
return makeNewIterable( new Iterator<Integer>() {
int i;
@Override
public boolean hasNext() { return i < bound; }
@Override
public Integer next() { return i++; }
@Override
public void remove() {
throw new UnsupportedOperationException(
"Not supported." );
}
} );
}

/**
* Returns an Iterable that counts from 0 up to and including the
* bound.
* @param bound Upper bound, inclusive, for this Iterable.
* @return An Iterable which counts 0..bound inclusive.
*/
public static Iterable<Integer> rangeI( final int bound ) {
return makeNewIterable( new Iterator<Integer>() {
int i;
@Override
public boolean hasNext() { return i <= bound; }
@Override
public Integer next() { return i++; }
@Override
public void remove() {
throw new UnsupportedOperationException(
"Not supported." );
}
} );
}

private static Iterable<Integer> makeNewIterable( final
Iterator<Integer> it ) {
return new Iterable<Integer>( ) {
@Override
public Iterator<Integer> iterator() {
return it;
}
};
}
}
 
L

Lew

Daniel said:
Not really:

int[] anArray;
for (int i: anArray) // Oops.

List<Integer> anArrayList;
for (int i: anArrayList) // oops.

I guess by "oops" you mean that the syntax is already valid in current Java.
I had a hard time seeing that as "oops", more like "huzzah".

<sscce>
package testit;

import java.util.ArrayList;
import java.util.List;
import java.util.Random;

public final class LoopGuru
{
public static void main( String [] args )
{
final Random ran = new Random();
int [] primitivos =
{ ran.nextInt(), ran.nextInt(), ran.nextInt(),
ran.nextInt(), ran.nextInt(), ran.nextInt(),
};

List <Integer> instances =
new ArrayList <Integer> (primitivos.length);

System.out.println( "array" );
System.out.print( "{ " );

for ( int ix : primitivos )
{
System.out.print( ix );
System.out.print( ", " );
instances.add( Integer.valueOf( ix ));
}
System.out.println( "}" );

System.out.println( "list" );
System.out.print( "{ " );

for ( int ix : instances )
{
System.out.print( ix );
System.out.print( ", " );
}
System.out.println( "}" );
}
}
</sscce>

Output:
array
{ 627089629, 1671919000, -211269067, -241006977, 1094855336, 1531172813, }
list
{ 627089629, 1671919000, -211269067, -241006977, 1094855336, 1531172813, }
 
J

Joshua Cranmer

markspace said:
This is a clever idea. I'll try this and see if it helps. BTW, I think
your test in hasNext() is incorrect. It should be !=, not ==, or maybe
<= or <, which will catch problems if the user calls next() too many
times and increments I over the bound.

My bad.
My version is at the end of this post.

If you really want to go all out, you could make three overloads of
range to emulate python's version:
range(n) = [0, n)
range(a, b) = [a, b)
range(a, b, step) = from a to b with step size step (i.e., the standard:
for (int i = a; a < b; a += step) [if step is positive]
for (int i = a; a > b; a += step) [if step is negative]
ERROR! [if step is 0]
)
 
R

Roedy Green

Uh.... Roedy these are in the language now. They support widening and
auto-unboxing too.

Oops. What is there right now is for ( Integer i: anArrayList )

What I was intending was this:

for ( int i : arrayList )
{
arrayList.put( i, i );
}

The problem I see now is the syntax would be ambiguous with unboxing
in a simple for:each.
--
Roedy Green Canadian Mind Products
http://mindprod.com

"For reason that have a lot to do with US Government bureaucracy, we settled on the one issue everyone could agree on, which was weapons of mass destruction."
~ Paul Wolfowitz 2003-06, explaining how the Bush administration sold the Iraq war to a gullible public.
 
A

Arne Vajhøj

Roedy said:
Oops. What is there right now is for ( Integer i: anArrayList )

for ( int i: anArrayList )

is also valid.
What I was intending was this:

for ( int i : arrayList )
{
arrayList.put( i, i );
}

Joshua's Range trick is a lot more elegant.
The problem I see now is the syntax would be ambiguous with unboxing
in a simple for:each.

Exactly.

Arne
 
M

markspace

Joshua said:
If you really want to go all out, you could make three overloads of
range to emulate python's version:
range(n) = [0, n)
range(a, b) = [a, b)
range(a, b, step) = from a to b with step size step (i.e., the standard:


I thought about those, but I don't use the latter two that often. It's
[0..n) that I find I use all the time.

BTW, JavaFX has a similar thing, actually a class called Sequence that
defined in javafxrt.jar. It's a tad harder to use though, since it's
designed for language support, not direct instantiation so much.

<http://java.sun.com/developer/technicalArticles/scripting/javafx/javafx_and_java/index.html>

Sequence<? extends Integer> seq =
Sequences.make(Integer.class, 2, 3, 5, 7, 11);
 
R

Roedy Green

Joshua's Range trick is a lot more elegant.

Often in refactoring code I have to undo a for:each because I need the
index. In my home brew language, Abundance, the index is always
available, but most of the time you don't need it.

This sounds pretty drastic, but for Java, perhaps the keyword index
could be reserved to let you get at the loop index of the immediately
enclosing for:each loop.


e.g.

for ( String s : arrayList)
{
if ( s.length() == 0 ) { arrayList.set( index, null ); }
}

That is roughly what I did in Abundance, translated into Javaesque
syntax, though in Abundance, s = x; translates to arraylist.set(
index, x ).

--
Roedy Green Canadian Mind Products
http://mindprod.com

"For reason that have a lot to do with US Government bureaucracy, we settled on the one issue everyone could agree on, which was weapons of mass destruction."
~ Paul Wolfowitz 2003-06, explaining how the Bush administration sold the Iraq war to a gullible public.
 
T

Tom Anderson

Mike said:
markspace said:
Just thinking out loud here, mostly. I seem to write a lot of the
following type of loop:

Object[] array ....
for( int i = 0; i < array.length; i++ ) {
....
}

What do you do with i, other than say

Object o = array;


Assign to an element of array.

array = new SomeClass(i);

Do a coordinated operation between two or more arrays.

array2 = array.toString();

However, I'm not convinced there enough simplification between the
existing and proposed syntax to justify another for-loop variant.


I like it - i'd use it fairly often. I certainly miss it now, to the point
where i often contemplate writing a little class to help me do it,
something like:

class Range implements Iterable<Integer> {
private final int start;
private final int end;
public Range(int start, int end) {
this.start = start;
this.end = end;
}
public Range(int end) {
this(0, end);
}
public Range(Collection c) {
this(c.size());
}
public Range(CharSequence s) {
this(s.length());
}
public Range(Object[] arr) {
this(arr.length);
}
public Iterator<Integer> iterator() {
return new Iterator<Integer>() {
int i = start;
public Integer next() {
if (!hasNext()) throw new NoSuchElementException();
int x = i;
++i;
return x;
}
public boolean hasNext() {
return i < end;
}
public void remove() {
throw new UnsupportedOperationException():
}
}
}
}

The only problem is that use of it involves a box-unbox on every
iteration.

The new syntax would be pure syntactic sugar - it wouldn't require any new
classes, or bytecodes, or class format changes, or changes to any other
part of the language. It seems like a harmless and beneficial addition to
me.

tom
 
T

Tom Anderson

That's an interesting idea. I wonder if for-each could be expanded to
include an Iterator too.

for( Interator<> i -> foos ) {
if( i.next().equals( badValue ) ) {
i.remove();
}
}

But this appears to have been deliberately excluded by the language
designers.

Not being able to for-loop over an Iterator, as opposed to an Iterable, is
also incredibly frustrating. I start with something like this:

for (String s: someCollectionOfStrings) {
fooBarDoStuff();
doSomethingOnlyForTheLastElement(); // needs a guard
}

And then i realsie that i can't do that - i have to rewrite the loop as a
while loop. Like:

Iterator<String> it = someCollectionOfStrings.iterator();
while (it.hasNext()) {
s = it.next()) {
fooBarDoStuff();
if (it.hasNext()) doSomethingOnlyForTheLastElement();
}

Which feels much less cohesive and more clunky to me.

If you want to use a traditional three-part for loop, you have to do
something bonkers like:

String s;
for (Iterator<String> it = someCollectionOfStrings.iterator(); it.hasNext() && ((s = it.next()) != null);) {
fooBarDoStuff();
if (it.hasNext()) doSomethingOnlyForTheLastElement();
}

Although if your collection contains nulls, you'll need to find a
different way of writing 'true' that has an assignment to s as a side
effect - you could just tack a || true on the end, i suppose. Or write
assignment to s twice, once at the start and once in the update clause.

I want to be able to do:

Iterator<String> it = someCollectionOfStrings.iterator()
for (String s: it) {
fooBarDoStuff();
if (it.hasNext()) doSomethingOnlyForTheLastElement();
}

tom
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,764
Messages
2,569,564
Members
45,039
Latest member
CasimiraVa

Latest Threads

Top