Proposal: JDK-8148917 Enhanced-For Statement Should Allow Streams

Ivan Gerasimov ivan.gerasimov at oracle.com
Thu Mar 14 02:01:52 UTC 2019


Hi Stuart!


On 3/13/19 5:45 PM, Stuart Marks wrote:
>
> On 3/12/19 4:32 PM, Ivan Gerasimov wrote:
>> If there were two new subtypes of Iterable introduced:  IterableOnce 
>> and IterableMultipleTimes, then all existing Iterables could be 
>> retrofitted to implement one of these.
>>
>> It wouldn't *automatically* solve the problem of 3rd party API, which 
>> accepts an Iterable and iterates it multiple times, but would provide 
>> a means to change that API in a straightforward way.
>>
>> Also, the static analysis tools could issue a suggestion for code 
>> that iterates Iterable more than once to switch to 
>> IterableMultipleTimes, so that it won't be possible to pass in an 
>> IterableOnce.
>>
>> It would also allow to strengthen the specification for 
>> IterableMultipleTimes and state that all classes implementing it must 
>> make it possible to obtain multiple iterators.
>
> Hi Ivan,
>
> This would be a cleaner type hierarchy, in the sense that it would 
> avoid the subtype-or-supertype issue that's being discussed in a 
> parallel segment of this thread. But practically speaking I don't 
> think it adds much value. Most Iterables can be iterated multiple 
> times; it seems to be the exceptional case that an Iterable is 
> once-only. (In the JDK, the examples of Scanner and Stream show that 
> things with once-only behavior avoided implementing Iterable at all.)
>
Yes, I agree that IterableOnce will likely be rare, comparing to 
IterableMany.
> While we could migrate the JDK classes to IterableMany (or whatever it 
> would be called), I think it's unrealistic to expect that all the 
> Iterable implementations out there in the wild would migrate. We'd 
> thus be left with Iterable and IterableMany meaning more-or-less the 
> same thing in perpetuity.
>
I'm thinking about a use case with a method that accepts Iterable and 
*needs* to traverse it multiple times.
(You actually gave such example in the proposal: assertThat(Iterable) 
from AssertJ).

With IterableMany it could be handled like this:

void foo(Iterable<Object> it) {
     if (!(it instanceof IterableMany)) {
         var list = new ArrayList<Object>();
         it.forEach(list::add);
         it = list;
}
     for (Object x : it) { ... }
     for (Object x : it) { ... }
}

On the other hand, checking if the argument is instanceof IterableOnce 
wouldn't help because the base class Iterable doesn't provide guaranties 
w.r.t number of traversals.

With kind regards,
Ivan

>
> By introducing IterableOnce, we can attract retrofits by once-off 
> things (like Scanner and Streams) and the uncommon occurrences of 
> once-off things like DirectoryStream that currently implement Iterable 
> can be migrated to IterableOnce. Everybody else can then just stay on 
> Iterable.
>
> s'marks
>

-- 
With kind regards,
Ivan Gerasimov



More information about the core-libs-dev mailing list