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

Reply via email to