Jdk 1.5 extended for loop problem.

C

Carl Howells

It seems that the extended for syntax added in Jdk 1.5 has one big issue
making it more difficult to use than it should be.

Consider the very useful new input class, java.util.Scanner. Scanner
implements the Iterator<String> interface. That means that if I just
want to tokenize a stream based on a fixed delimiter pattern, treating
all the tokens as String objects, I can just treat the Scanner as an
Iterater<String>, and be perfectly happy with the results.

But I can't do that with the new extended for loop syntax. Here's an
example of what I'd like to do, but currently can't:

import java.util.*;

public class Test
{
public static void main(String [] args) throws Exception
{
Scanner sc = Scanner.create(System.in);

for (String s : sc)
{
System.out.printf("'%s'\n", s);
}
}
}

The problem is that the extended for syntax only allows instances of
Iterable (And arrays... Have those been changed to implement Iterable,
or does the syntax allow arrays as well as Iterable objects?) as the
object to iterate over. This seems unnecessarily restrictive. This led
to me writing some exceptionally stupid code just to be able to use the
much cleaner for syntax:

import java.util.*;

public class Test
{
public static void main(String [] args) throws Exception
{
Scanner sc = Scanner.create(System.in);

for (String s : new IteratorReturner<String>(sc))
{
System.out.printf("'%s'\n", s);
}
}

static class IteratorReturner<E> implements Iterable<E>
{
private Iterator<E> it;

IteratorReturner(Iterator<E> i)
{
it = i;
}

public Iterator<E> iterator()
{
return it;
}
}
}

I mean, that's just stupid. The extra class adds no semantic value. It
doesn't make things clearer. It's just a stupid hack to make the types
what the compiler wants.

Consider how many API's return instances of Iterator or Enumeration,
rather than a collection that implements Iterable. Why is having an
adaptor class like the one needed above a cleaner solution than just
allowing the extended for syntax to iterator over instances of Iterator
and Enumeration?

Does anyone else think that this is a big enough issue that it should be
fixed? Is there anything about this in Sun's bug or RFE databases? I
tried searching, but the search engine for those databases is severely
limited.
 
?

=?ISO-8859-1?Q?Daniel_Sj=F6blom?=

Carl said:
Consider how many API's return instances of Iterator or Enumeration,
rather than a collection that implements Iterable. Why is having an
adaptor class like the one needed above a cleaner solution than just
allowing the extended for syntax to iterator over instances of Iterator
and Enumeration?

Does anyone else think that this is a big enough issue that it should be
fixed?

Definitely. It might even be better to forget about Iterable altogether.
What if I want a ranged Iterator over a collection? Does that mean I
can't use the new for loop?

If the for loop accepted only an Iterator or Enumeration, the syntax
would only be slightly less terse, but infinitely more flexible:

for (T t : obj.iterator()) { }

instead of the very limited, collection oriented:

for (T t : collection) { }
 
N

nos

Carl Howells said:
It seems that the extended for syntax added in Jdk 1.5 has one big issue
making it more difficult to use than it should be.

Consider the very useful new input class, java.util.Scanner. Scanner
implements the Iterator<String> interface. That means that if I just
want to tokenize a stream based on a fixed delimiter pattern, treating
all the tokens as String objects, I can just treat the Scanner as an
Iterater<String>, and be perfectly happy with the results.

But I can't do that with the new extended for loop syntax. Here's an
example of what I'd like to do, but currently can't:

import java.util.*;

public class Test
{
public static void main(String [] args) throws Exception
{
Scanner sc = Scanner.create(System.in);

for (String s : sc)
{
System.out.printf("'%s'\n", s);
}
}
}
Don't you need a "new" in there somewhere (i b nube). Does it compile?
The problem is that the extended for syntax only allows instances of
Iterable (And arrays... Have those been changed to implement Iterable,
or does the syntax allow arrays as well as Iterable objects?) as the
object to iterate over. This seems unnecessarily restrictive. This led
to me writing some exceptionally stupid code just to be able to use the
much cleaner for syntax:

import java.util.*;

public class Test
{
public static void main(String [] args) throws Exception
{
Scanner sc = Scanner.create(System.in);

for (String s : new IteratorReturner<String>(sc))
{
System.out.printf("'%s'\n", s);
}
}

static class IteratorReturner<E> implements Iterable<E>
{
private Iterator<E> it;

IteratorReturner(Iterator<E> i)
{
it = i;
}

public Iterator<E> iterator()
{
return it;
}
}
}

I mean, that's just stupid. The extra class adds no semantic value. It
doesn't make things clearer. It's just a stupid hack to make the types
what the compiler wants.

Consider how many API's return instances of Iterator or Enumeration,
rather than a collection that implements Iterable. Why is having an
adaptor class like the one needed above a cleaner solution than just
allowing the extended for syntax to iterator over instances of Iterator
and Enumeration?

Does anyone else think that this is a big enough issue that it should be
fixed? Is there anything about this in Sun's bug or RFE databases? I
tried searching, but the search engine for those databases is severely
limited.
 
C

Carl Howells

nos said:
Carl Howells said:
import java.util.*;

public class Test
{
public static void main(String [] args) throws Exception
{
Scanner sc = Scanner.create(System.in);

for (String s : sc)
{
System.out.printf("'%s'\n", s);
}
}
}

Don't you need a "new" in there somewhere (i b nube). Does it compile?

Well, no, it doesn't compile, and that's the point of my post. But it
fails to compile because sc isn't an instance of Iterable, not for any
other reason.

There are no other errors in that code. There's no use of the "new"
keyword because I never instantiate an object directly by calling its
constructor.
 
C

Chris Uppal

Carl said:
The problem is that the extended for syntax only allows instances of
Iterable (And arrays... Have those been changed to implement Iterable,
or does the syntax allow arrays as well as Iterable objects?) as the
object to iterate over. This seems unnecessarily restrictive.

Now you mention it, it does indeed seem stupid.

Does anyone know if the C# feature, from which it was presumably copied, has an
analogous problem ?

Does anyone else think that this is a big enough issue that it should be
fixed?

I think so. But it suggests that an even more important candidate for fixing
is the review process itself. How did this one slip through the net ?

(I'm not in general a fan of the new extensions -- although the loop thing
seems pretty benign -- but if we're going to have them at all, then let's do
them right.)

-- chris
 
A

Adam P. Jenkins

Chris said:
Carl Howells wrote:




Now you mention it, it does indeed seem stupid.

Does anyone know if the C# feature, from which it was presumably copied, has an
analogous problem ?

I'm not sure why you think this feature was copied from C#. I've been
using languages with some equivalent of foreach since way back when. I
think QBasic had some sort of foreach, Perl does, Python does, TCL, Bash
Lisp, Javascript ... pretty much every high-level language I can think of.

I agree though that the Java one should work with Iterators and not
require an Iterable object. I would say it should require an array, an
object which implements Iterable, or an iterator. I would still like
for there to be an Iterable interface so that I don't always have to add
".iterator()" for the common cases. But not accepting Iterator means I
can't use the for loop with any existing classes which return Iterators
yet don't implement Iterable, or classes which may have different
methods which return different Iterators.
 
C

Chris Uppal

Adam said:
I'm not sure why you think this feature was copied from C#. I've been
using languages with some equivalent of foreach since way back when.

Oh, I'm not saying the *concept* of foreach originated in C# -- it clearly
didn't. But I don't remember any calls for "foreach" to be added to Java
until after C# had come out, and right from the start suggestions for adding it
referred to the C# facility. Which is why I've assumed that the immediate
ancestor of the new Java feature was C#. I certainly could be wrong; I'm not
privy to the discussions that lead to its introduction.

That aside, I'd still like to know if C# *does* suffer from an analogous
problem.

I agree though that the Java one should work with Iterators and not
require an Iterable object. I would say it should require an array, an
object which implements Iterable, or an iterator. I would still like
for there to be an Iterable interface so that I don't always have to add
".iterator()" for the common cases.

I think (but it's too late now, I suppose) that it'd be better to handle just
arrays and Iterator objects. Given the choices:

1) Handle arrays and Iteratable only.
2) Handle arrays and Iterator only.
3) Handle arrays, Iterator *and* Iterable.

(1) is -- as it seems everyone in this thread agrees -- inadequate.

(2) is completely flexible, handles all iteration in a uniform manner (which I
consider important), but at the slight cost of a little more typing in a common
case.

(3) has the advantage to requiring less typing on one common case, but at the
cost of breaking the uniformity of use of iteration. Also potentially
confusing. Also requires more complex specification since there's nothing to
stop an object being both an Iterator and an Iterable.

So, for me, (2) is to be preferred over (3).

-- chris
 
A

Adam P. Jenkins

Chris said:
Adam P. Jenkins wrote:




Oh, I'm not saying the *concept* of foreach originated in C# -- it clearly
didn't. But I don't remember any calls for "foreach" to be added to Java
until after C# had come out, and right from the start suggestions for adding it
referred to the C# facility. Which is why I've assumed that the immediate
ancestor of the new Java feature was C#. I certainly could be wrong; I'm not
privy to the discussions that lead to its introduction.

That aside, I'd still like to know if C# *does* suffer from an analogous
problem.





I think (but it's too late now, I suppose) that it'd be better to handle just
arrays and Iterator objects. Given the choices:

1) Handle arrays and Iteratable only.
2) Handle arrays and Iterator only.
3) Handle arrays, Iterator *and* Iterable.

(1) is -- as it seems everyone in this thread agrees -- inadequate.

(2) is completely flexible, handles all iteration in a uniform manner (which I
consider important), but at the slight cost of a little more typing in a common
case.

(3) has the advantage to requiring less typing on one common case, but at the
cost of breaking the uniformity of use of iteration. Also potentially
confusing. Also requires more complex specification since there's nothing to
stop an object being both an Iterator and an Iterable.

So, for me, (2) is to be preferred over (3).

The main point of the new for loop is for syntactic convenience, and (2)
dilutes that too much for my taste. The case where I'm just calling
iterator() on a collection is *by far* the most common case at least in
my experience. I assume this is true for many others, which is why the
feature ended up being designed the way it has. Still, there are enough
other cases where I get an Iterator in some other way that I would like
the for loop to work for those cases too. So (3) seems best to me.

I must admit I didn't think of the problem of an Iterator being
Iterable. I don't think it adds much complexity to the spec though:
just declare that the Iterator interface takes precedence over Iterable
(or vice versa.) It's such a borderline case that I don't think most
programmers would even need to think about it.
 
?

=?ISO-8859-1?Q?Vahur_Sinij=E4rv?=

Daniel said:
If the for loop accepted only an Iterator or Enumeration, the syntax
would only be slightly less terse, but infinitely more flexible:

for (T t : obj.iterator()) { }

instead of the very limited, collection oriented:

for (T t : collection) { }

The colon could have been replaced by 'in' keyword, which would lead to
more readable code:

for (T t in collection) {}

or

for (T t in obj.iterator()) {}

i'm not sure the last one would have been more readable ...
 
A

Adam P. Jenkins

Vahur said:
The colon could have been replaced by 'in' keyword, which would lead to
more readable code:

for (T t in collection) {}

or

for (T t in obj.iterator()) {}

i'm not sure the last one would have been more readable ...

The rationale for using colon instead of a new keyword is backward
compatibility. The current syntax doesn't break any existing code,
whereas making 'in' be a keyword would break any existing code that used
'in' as an identifier.
 

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,755
Messages
2,569,537
Members
45,020
Latest member
GenesisGai

Latest Threads

Top