No-reuse and stream destructuring as (first, rest) pair

Ali Lahijani alahijani at gmail.com
Sun Nov 25 14:04:28 PST 2012


The no-reuse restriction on stream operations has been recently pushed. So
for example, the following code now throws an exception.

Stream p = ..
Stream c1 = p.map(...);
Stream c2 = p.filter(...);

I think from the perspective of stream users, it makes much sense for
operations that are supposed to work on the whole stream. If they do not
care about the lazy nature of streams, they could argue that the stream
must have been drained by the previous operation.

But findFirst() and findAny() invalidating the whole stream does not seem
so fair. I think end users reasonably expect lazy streams to be at least as
flexible and usable as eager codes they now write with iterator and its kin.

For example, this is a frequent idiom:

Iterator<T> it = ...;
if (!it.hasNext()) throw new NoResultsException();
T result = it.next();
if (it.hasNext()) throw new MultipleResultsException();
return result;

Current findFirst() and findAny() methods return an Optional<T> which gives
me an equivalent for the first hasNext() call, but not the second one. And
because of the no-reuse rule, there is no hope for obtaining any more
information from the stream itself. This is just an example, the point is,
end users expect the rest of the stream to be somehow recoverable.

IMO since the stream is being marked as invalid after a call to findFirst()
or findAny(), it would be most natural if the rest of the stream was also
actually consumed (lazily) by the call, and attached to the returned
object, so we already have

T first = stream.findFirst().get();

we will also have

Stream<T> rest = stream.findFirst().rest();

This has an IMO pleasant side effect: the return type Optional<T> will no
longer look like an option monad at all. It is a (first, next) pair. It
will finally be renamed to something else, and with that move a lot of
problems will be put to rest :)

I am not familiar enough with the internals of streams to say whether this
 can be implemented easily, but from the PoV of stream users I think it's
the most natural thing.


More information about the lambda-libs-spec-observers mailing list