What do you think about the for-each loop?

R

Red Orchid

The reference document :
http://java.sun.com/j2se/1.5.0/docs/guide/language/foreach.html

The above document says :

"the for-each construct combines beautifully
with generics. It preserves ..............
..... for nested iteration! Feast your eyes:"


I can 'feast' my eyes on the following 'beutifull'
code. But it is an error.
///////////////////////////////////////
void swap(int i, int j) {
int t;
t = i;
i = j;
j = t;
}
....
int[] aArr = new int[]{7, 1, 2};
int[] bArr = new int[]{6, 1, 5};

for (int a : aArr)
for (int b : bArr)
if (a < b) {
swap(a, b);
}
/////////////////////////////////////////

The for-each loop seems to be very prone to error.

Can you feel confident that you will use the for-each
loop correctly in a large code?

Of cource, the above document says :

" .. These shortcomings were known by the designers,
who made a conscious decision to go with a clean,
simple construct that would cover the great majority
of cases."


a clean, simple construct ??
What do you think about the for-each loop ?

Thanks.
 
R

Red Orchid

Correct :

int[] aArr = new int[]{7, 1, 2};
int[] bArr = new int[]{6, 1, 5};

for (int a : aArr)
for (int b : bArr)
if (a < b) {
int t;
t = i;
i = j;
j = t;
}
 
R

Red Orchid

Sorry.
Correct :

int[] aArr = new int[]{7, 1, 2};
int[] bArr = new int[]{6, 1, 5};

for (int a : aArr)
for (int b : bArr)
if (a < b) {
int t;
t = a;
a = b;
b = t;
}
 
T

Tor Iver Wilhelmsen

Red Orchid said:
void swap(int i, int j) {
int t;
t = i;
i = j;
j = t;
}

What does that no-op method have to do with foreach or generics?
The for-each loop seems to be very prone to error.

Where? How? You have not shown that to be the case.
 
T

Tor Iver Wilhelmsen

Red Orchid said:
for (int a : aArr)
for (int b : bArr)
if (a < b) {
int t;
t = a;
a = b;
b = t;
}

It's still a no-op, you are just manipulating variables which get
reset at the next iteration through the loop. Did you think you were
in any way affecting the arrays here? You are not.
 
R

Red Orchid

What does that no-op method have to do with foreach or generics?

I intended to illustrate no-op(no operation) inside
for-each loop. I admit that my example is bad one.
Therefore I corrected my example in my previous posting.


My point is as follows :

///////////////////////////////////////
String parse(String source, ... ) {
....
}

String[] sArr = .. ;

for (String s : sArr) {
...
s = .. ; // #1
...
}
...

for (String s : sArr) {
...
s = parse(s, ... ); // #2
...
}
/////////////////////////////////////////

There is strong possibility that #1 is regarded
as modifying some element of "sArr" array.
In a large code, it is very hard to detect that
some assignment statement is no-op.

The next.
Let's suppose that there is a bug in the above
for-each loop of #2.

There will be doubt concerning the bug-free of
"parse" method if #2 is regarded as not no-op.
In this case, it becomes hard to debug the for-
each loop. (Of cource, it was obvious that the
"swap" of my previus posting has a bug.)

Where? How? You have not shown that to be the case.


I think that for-each loop has to allow an assignment
statement like #1 as not no-op.

What is your opinion ?
Thanks.
 
P

Patricia Shanahan

Red Orchid wrote:
....
I think that for-each loop has to allow an assignment
statement like #1 as not no-op.

What is your opinion ? Thanks.

Consider this in terms of the previous for-loop. A
sufficiently incompetent programmer could write:

for (int i=0; i<sArr.length; i++) {
String s = sArr;
...
s = .. ; // #1
...
}

Presumably this indicates a defect in the design of
for-loops, especially the ability to create and manipulate
locally declared variables.

Every foreach discussion I've seen, including the page
you referenced in your first message, indicates that it is
not a universal replacement for the for-loop, but something
that removes a bunch of busy-work from some simple cases. My
own plan is to use foreach where it works well and makes my
intent clearer, such as iteration through a List without
deletion, and stick with other loop forms everywhere else.

Patricia
 
O

opalpa

The thing that is bad about java's for each is that it should be:

for (String s in stringCollection) {

}

instead of

for (String s : stringCollection) {

}

Me, myself, and I, we have started to write:


for (String s : /* in */ stringCollection) {

}


and can now remember what goes where.
 
P

Philipp Gressly

fg said:
In this case, Sun would need a new keyword : "in", and it's hard to add a
keyword to an existing language..

Why not adding a new keyword? Sun did it with the "assert" Keyword since
jsdk 1.4 ;-)
If it is realy useful, I think, Sun has to do it. And in this case I
think it is quiet useful.
 
F

fg

The thing that is bad about java's for each is that it should be:
for (String s in stringCollection) {

}

In this case, Sun would need a new keyword : "in", and it's hard to add a
keyword to an existing language..
 
F

fg

Why not adding a new keyword? Sun did it with the "assert" Keyword since
jsdk 1.4 ;-)

Sorry, I don't use assertions, so I didn't know...
If it is realy useful, I think, Sun has to do it. And in this case I think
it is quiet useful.

Assertion was a new feature, and Sun had no way but to add this Keyword.
In the foreach case, Sun did it without any new keyword, and your
proposition to add "in" is just for convenience purpose, since you're used
to write it this way...
I think that Sun did not want to bother adding a new keyword, when it is
unnecessary, since it may have forced people rewriting some parts of their
code : they already did it with "assert", and it may be enough for now...
 
G

Guest

The thing that is bad about java's for each is that it should be:

for (String s in stringCollection) {

}

instead of

for (String s : stringCollection) {

}

Yes. The ':' in java's for each should be read as "in".
But the ':' in the fourth line of the following should be
read as "else".

public class ForEachTest {
public static void main(String[] args) {
for (String arg : args) {
System.out.println( arg.equals("blank") ? "" : arg );
}
}
}

I realize that "context is everything"... Still .....

George
 
T

Tor Iver Wilhelmsen

fg said:
Assertion was a new feature, and Sun had no way but to add this Keyword.

Yes, but it still broke a lot of software (read: JUnit which had to
rename a method to "assertTrue"). Perhaps that was why they didn't do
it this time around: I cannot count the number of times I've called an
inputstream variable for "in".
 
T

Tor Iver Wilhelmsen

Red Orchid said:
There is strong possibility that #1 is regarded
as modifying some element of "sArr" array.
In a large code, it is very hard to detect that
some assignment statement is no-op.

Yes, but the same warning - don't abuse count variables for anything
else - holds just as well for the existing loop constructs. The
"foreach" syntax is just new. It does not change anything.

The construct is merely syntactic sugar for initializing and promoting
an iterator.

(There should perhaps be a -Xlint warning for it, at best, like
"Warning: Loop variable assigned to in body". Java programmers know
that Java's pointers do not work like C pointers, where you actually
*can* change the array/collection value via a pointer and have to be
VERY careful about what you do.)
 
B

Bent C Dalager

Yes, but it still broke a lot of software (read: JUnit which had to
rename a method to "assertTrue"). Perhaps that was why they didn't do
it this time around: I cannot count the number of times I've called an
inputstream variable for "in".

Seeing as this would require them to rename System.in, my guess is a
new keyword "in" was just completely out of the question.

Cheers
Bent D
 
D

Dale King

Answering the more general question in the subject, I would like to see
and even suggested to Sun that the same construct might be useful for
I/O operations.

Consider this loop:

for( int i; ( i = inputStream.read() ) != -1; )
{
byte b = (byte)i;

How about being able to replace that with:

for( byte b : inputStream )
{

And you could do a similar thing for reading lines with BufferedReader.
 
A

Adam P. Jenkins

Dale said:
Answering the more general question in the subject, I would like to see
and even suggested to Sun that the same construct might be useful for
I/O operations.

Consider this loop:

for( int i; ( i = inputStream.read() ) != -1; )
{
byte b = (byte)i;

How about being able to replace that with:

for( byte b : inputStream )
{

And you could do a similar thing for reading lines with BufferedReader.

Actually the current foreach construct is already capable of this;
inputStream would just need to implement java.lang.Iterable. So this
would really be a request for a library enhancement.

For me, the main limitation to foreach's usefulness is that it doesn't
work for Iterators. There are many classes which have more than one
function that returns an Iterator, to provide different views of an
object. The fact that foreach requires an object which implements
Iterable means that only one of these views can be iterated over with
foreach, and the other views have to be iterated using the old style.

List<String> list;

for (String s : list) {
// works fine
}

for (String s : list.listIterator(3)) {
// no way to do this with foreach
}

I suppose this could also be fixed with a library change, by making
Iterators implement Iterable, but that would be nasty.

Adam
 
G

Guest

Dale King said:
Answering the more general question in the subject, I would like to see
and even suggested to Sun that the same construct might be useful for I/O
operations.

Consider this loop:

for( int i; ( i = inputStream.read() ) != -1; )
{
byte b = (byte)i;

How about being able to replace that with:

for( byte b : inputStream )
{

And you could do a similar thing for reading lines with BufferedReader.

Yes, why not? It's so logical that I would expect it to be the case.
 
D

Dale King

Adam said:
Actually the current foreach construct is already capable of this;
inputStream would just need to implement java.lang.Iterable. So this
would really be a request for a library enhancement.

That would be a bit inefficient as you would be introducing an unneeded
object for every byte that is read.
For me, the main limitation to foreach's usefulness is that it doesn't
work for Iterators.

There is a potential of confusion if it worked for iterators. I can see
some confusion when you start getting into nested loops.
 

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,754
Messages
2,569,528
Members
45,000
Latest member
MurrayKeync

Latest Threads

Top