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