<T> Stream.fromForEach(Consumer<Consumer<T>>)
Peter Levart
peter.levart at gmail.com
Wed May 25 11:23:11 UTC 2022
Hi,
On 23/05/2022 14:53, Brian Goetz wrote:
> ...
>
> Are there any useful Consumer<Consumer<T>> in the wild, that are
> actually typed like that? I doubt it (there are many things
> convertible to it, though.) Which suggests it might be fruitful to
> define a FI:
>
> interface PushSource<T> {
> void accept(Consumer<? extends Consumer<T>> pusher);
> }
>
> static<T> Stream<T> fromPush(PushSource<T> source) { ... }
>
> and Iterable::forEachRemaining and Optional::ifPresent will convert to
> it.
>
>
...the PushSource would probably be just the following (a replacement
for Consumer<Consumer<T>>):
interface PushSource<T> {
void accept(Consumer<T> consumer);
}
The outer Consumer is not that problematic, IMO, since it is subject of
conversion from any similar signature via lambdas/method references as
easily as PushSource. The inner Consumer type is more problematic. For
example, suppose one would have the following API:
interface Listener {
void listen(String token);
}
record Parser(String text) {
void parse(Listener listener) {
for (var token : text.split(" ")) {
listener.listen(token);
}
}
}
...to convert a Parser instance `parser` to a Stream of tokens, one
would have to do something like this:
var parser = new Parser("1 2 3 4");
var stream = Stream.fromForEach(consumer -> parser.parse(consumer::accept));
...and then the type of stream would be inferred as Stream<Object>, not
Stream<String> as one would like. Type hinting would be necessary:
var stream = Stream.<String>fromForEach(consumer ->
parser.parse(consumer::accept));
I don't believe Java type system allows doing such things more elegantly.
One point to highlight is also that such method is only suitable for
"finite" generators. A generator that emits infinite number of elements
would have no way to stop emitting them although the resulting Stream
was later shortened with .limit(max) or .takeWhile(predicate), ... Such
Stream would never stop. This could be solved by a warning in the
javadoc though. Or by something that project Loom could provide in the
form of continuation?
As to the name, `generate` is taken by the generate(Supplier<T>
supplier) form, but overload is technically possible, since it differs
by parameters of unrelated type and number of parameters of the
@FunctionalInterface methods (Supplier vs. Consumer). No conflicts
should be expected.
Regards, Peter
More information about the core-libs-dev
mailing list