I’m going to challenge the consensus a little bit. First, Rémi's example can be 
simplified to this one method which fails to compile with the same error 

private static Optional<?> simple1(
 Optional<String> o, Function<String, Optional<?>> f
) {return o.flatMap(f);} 

Second, although not in the webrev, Optional::map and Optional::flatMap can be 
implemented without needing any unchecked casts:

public <U, R extends U, O extends Optional<R>> Optional<U> flatMap(
 Function<T, O> mapper
) {
 return ofNullable(isPresent() ? mapper.apply(get()).orElse(null) : null);
public <P, Q extends P> Optional<P> map(
 Function<T, Q> mapper
) {
 return ofNullable(isPresent() ? mapper.apply(get()) : null);

These are fully, soundly compile-time typed methods with all types exposed and 
completely under the control of the programmer.

Now, to see if the signature of flatMap is truly the problem, it’s possible to 
write the simple1 method as a map followed by a flatMap with the identity 
function, like this:

private static Optional<?> simple2(
 Optional<String> o, Function<String, Optional<?>> f
) {return o.map(f).flatMap(Function.identity());}

In this version, the call to flatMap and its argument don’t use any wildcard 
types, both in the version above and in java.util.Optional[1]. Despite that, 
the compiler from jdk1.8.0_102 still gives an error[2] from the flatMap method 
call. This is quite a curious result as here flatMap and identity are reusing 
types that are already used by type inference. If this isn’t sound but using 
wildcards is then I would really like to see that counterexample!

Some questions that have arisen (and my answers):

Should APIs account for types that are not denotable in source code? I’d say 
no, such types are bugs in the language.

Can non-denotable types be eliminated at the library level by adding more 
wildcards? Unlikely, as such types come from using wildcards to begin with.

Is there a bug in flatMap or is the bug in the language specification? Compared 
to one simple method, type inference rules are much harder to understand and 
thus more likely to contain undiscovered problems.

What is gained if these wildcards are added? Although simple1 and simple2 would 
compile, you still can’t do anything interesting like calling orElse or 

public static void main(String[] args) {
 Optional<String> foo = Optional.ofNullable(args[0]);
 Object o1 = simple1(foo, s -> foo).orElse(o1 = null);
 Object o2 = simple2(foo, s -> foo).orElseGet(() -> null);

Won’t compile. As far as I can tell, there is no real upside to this change.

Thanks for your consideration!

[0] Error:(18, 20) java: method flatMap in class java.util.Optional<T> cannot 
be applied to given types;
  required: java.util.function.Function<? super 
  found: java.util.function.Function<java.lang.String,java.util.Optional<?>>
  reason: cannot infer type-variable(s) U
    (argument mismatch; 
java.util.function.Function<java.lang.String,java.util.Optional<?>> cannot be 
converted to java.util.function.Function<? super 

[1] The <? super T> type can be discounted as its presence doesn’t make a 
difference in this case.

[2] Error:(21, 27) java: method flatMap in class wildcards.another.Optional<T> 
cannot be applied to given types;
  required: java.util.function.Function<wildcards.another.Optional<?>,O>
  found: java.util.function.Function<java.lang.Object,java.lang.Object>
  reason: inference variable O has incompatible bounds
    equality constraints: wildcards.another.Optional<?>,T
    upper bounds: wildcards.another.Optional<capture#11 of ?>,java.lang.Object

Have a nice day, 

Sent from Mail for Windows 10

From: Stuart Marks
Sent: Saturday, October 8, 2016 02:28
To: Stefan Zobel
Cc: core-libs-dev
Subject: Re: RFR(s): 8152617 add missing wildcards to Optional or() andflatMap()

On 10/7/16 3:12 PM, Stefan Zobel wrote:
>> ... After having looked at lots of generic APIs, it seems to me that a
>> style has emerged where wildcards are used whenever possible, and type
>> parameters are used only when necessary, ...
> Yes, I'm familiar with that kind of reasoning (I think Josh Bloch stated
> that principle in "Effective Java"). But, to be honest, I never thought
> that it should apply as a strict rule in all circumstances.

Yep, it's in Effective Java, near the end of Item 28:

     “As a rule, if a type parameter appears only once in a method
     declaration, replace it with a wildcard.”

> Rhetorical question: do you really think that a signature employing 3
> wildcards is easier to understand for the proverbial "average Joe" than
> a bounded type parameter that expresses the sub-type relationship clearly?
> I do not.
> But anyway, you probably have to follow the established "style".
> It's just too bad that most Java programmers I know won't understand the
> proposed signature of 'flatMap'.

Turns out that Rémi's example exposes the difference between the wildcard 
approach and the type-parameter approach. Returning to the example,

     Optional<Integer> oi = Optional.empty();
     Function<Number, Optional<StringBuilder>> fm = n -> Optional.empty();
     Optional<CharSequence> ocs = oi.flatMap(fm);

If the flatMapper function itself has a wildcard type, for example,

     Function<Number, Optional<? extends CharSequence>> fm = n -> 

then this will still work with the wildcard approach but fail with the 
type-parameter approach. As Rémi also pointed out, a wildcarded type can result 
from the capture of a type with a wildcarded type parameter.

Based on this, I believe the nested wildcard approach to be the correct one.


Reply via email to