flatMap ambiguity
Dan Smith
daniel.smith at oracle.com
Tue Feb 26 13:47:10 PST 2013
A thread on lambda-dev highlighted a problem with the overloading of flatMap:
<R> Stream<R> flatMap(FlatMapper<? super T, R> mapper)
IntStream flatMap(FlatMapper.ToInt<? super T> mapper)
LongStream flatMap(FlatMapper.ToLong<? super T> mapper)
DoubleStream flatMap(FlatMapper.ToDouble<? super T> mapper)
These functional interfaces have corresponding descriptors:
(T, Consumer<R>)->void (R is inferred)
(T, IntConsumer)->void
(T, LongConsumer)->void
(T, DoubleConsumer)->void
This violates the general rule that overloading with functional interfaces of the same shape shouldn't use different parameter types. Various ambiguities result:
- "(x, sink) -> sink.accept(10)" is compatible with all the primitive consumers, and we have no way to disambiguate (the new most-specific rules handle this sort of thing with return types, but are not designed to decide which type is "better" for an arbitrary block of code).
- "(x, sink) -> sink.accept(22.0)" is compatible with "(T, DoubleConsumer)->void", and leads "(T, Consumer<R>)->void" to be provisionally applicable -- we don't check the body at all in that case, until we've had a chance to look at the target type of the 'flatMap' invocation and figure out what R is supposed to be. So, again, an ambiguity will occur.
It would probably be best to give the primitive versions distinct names.
---
Note also that an invocation like the following will always produce a Stream<Object>:
stream.flatMap((x, sink) -> sink.accept("x")).filter(...)....
Inference is forced to resolve R without knowing anything about it, and so it must go with the default "Object".
The only way to get useful information about R is to derive bounds from the body of the lambda, and that's simply not something we can do in general.
I don't know what to recommend in this case, except perhaps that this method inherently depends on some explicit typing (e.g., "(String x, Consumer<String> sink) -> ...").
—Dan
More information about the lambda-libs-spec-observers
mailing list