The future of foreach

I want to talk about the enhanced for ('foreach') loop, an immensely popular construct. Many people are surprised to find that it only accepts Iterable expressions (and arrays, which I'll ignore). Why not also Iterators?

The JSR201 Expert Group considered this issue at length. foreach is syntactic sugar; the compiler generates an iterator() and a loop variable and a basic for loop in its place. The primary reason against passing an Iterator to foreach is that the user-provided body could modify it during iteration, and so break the compiler's assumptions about its generated code:

Iterator i = myList.iterator();
for (Object o : i) { /\* Maybe I'll just call i.remove() here, it'll be fun \*/ }

By requiring Iterables, JSR201 essentially placed safety above raw functionality. But even with Iterables, user code can still interfere with the compiler's code. A Collection passed to foreach can be modified concurrently and most Collection implementations aren't synchronized internally, so the compiler-generated iterator could break.

So, given that interference is possible with Iterables, and given that using Iterators would be very convenient, maybe we should dial down the safety a little to add some functionality. I'm not proposing any changes now, but I am keeping an open mind on Iterators. I control for the fact that people who want Iterator support shout the loudest :-)

(The argument against interference from user code is also why the loop variable isn't visible. This decision is very sensible.)

Comments:

It's already relatively easy to work around that restriction if we need to: Iterable ib = new Iterable() { public Iterator iterator() { return i; } } ; for( Object o : ib ) { ... } And if any of the closure proposals get up then it will be even easier. So although I'm not particularly concerned about the current restrictions, I'd say to drop them. Since it's so easy (but ugly) to avoid the restrictions, it's pretty hard to argue that they're giving much benefit. Compilers/IDEs can detect that you refer to the iterator inside the loop and add a warning if appropriate.

Posted by Tim Vernum on November 08, 2006 at 02:54 PM PST #

Alex, if you talk about changes to forEach, please consider a version that reliably closes the iterator. It's prerequisite if we want to build useful iterables such as "all lines in a file" or "all database records matching this query". I sketched an implementation here: https://jdk-collaboration.dev.java.net/servlets/ProjectForumMessageView?messageID=14881&forumID=1463. Unsurprisingly "closed will not be fixed" unless someone changes the lang spec. Thanks Matthias

Posted by Matthias Ernst on November 08, 2006 at 05:42 PM PST #

I miss Iterator.remove(). Maybe this would be okay?
for ( Object o : myList )
{
  for:remove(o);
}

Posted by Julius Davies on November 09, 2006 at 02:54 AM PST #

In the same spirit, for:index() would be useful sometimes.

Posted by George on November 14, 2006 at 07:44 PM PST #

All my projects contain a helper class to adapt an Iterator to a Iterable. I find this very annoying, please do relax it.

Posted by Luis Eduardo V. Matta on November 25, 2006 at 09:58 PM PST #

Post a Comment:
Comments are closed for this entry.
About

Alex Buckley is the Specification Lead for the Java language and JVM at Oracle.

Search

Categories
Archives
« April 2014
SunMonTueWedThuFriSat
  
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
   
       
Today
Feeds