On 10/7/16 11:23 AM, Paul Sandoz wrote:
   flatMap(Function<? super T, ? extends Optional<? extends U>> mapper)

Optional is final so why do you need to express “? extends Optional” ?

The short answer is, it doesn't work if you don't have it. :-)

The theoretical answer is that in this context, "? extends P<Q>" means "some subtype of P<Q>" and not necessarily just a subclass of P.

(And even though Optional is final, it's not "permanently final" in that a hypothetical future version of the class library might change it to non-final, allowing subclasses.)

This issue is covered in Angelika Langer's Generics FAQ entry, "What do multi-level (i.e., nested) wildcards mean?" [1] Note that the answer begins, "It depends." :-) I also note in passing that I've read this about five times and I'm still not quite sure I understand it entirely.

For me, the best explanation comes from looking at examples. First, the history is that the signature in Java 8 is:

  #1    flatMap(Function<? super T, Optional<U>> mapper)

I believe Rémi originally proposed something like this (although it was about or(), the same issue applies to flatMap()):

  #2    flatMap(Function<? super T, ? extends Optional<U>> mapper)

The suggested fix that ended up in bug report was this:

  #3    flatMap(Function<? super T, Optional<? extends U>> mapper)

But this doesn't work for reasons I explain below. Finally, I'm proposing:

  #4    flatMap(Function<? super T, ? extends Optional<? extends U>> mapper)

In researching old email threads and chasing links, I ran across an example from Stefan Zobel [2] that fails with #3. He had an alternative that didn't seem quite right to me, so I ended up with #4.

I've adapted Stefan's example as follows:

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

The flatmapper function 'fm' returns Optional<StringBuilder>. In the assignment on the last line, U is CharSequence, so we can compare this to the various signatures shown above with U filled in.

Case #1 fails because Optional<StringBuilder> is incompatible with Optional<CharSequence>. This is the usual "generics are invariant thing". Even though SB is a subtype of CS, Optional<SB> isn't a subtype of Optional<CS>.

Case #2 fails because adding a wildcard there doesn't help matters, since Optional<SB> is still unrelated to Optional<CS>.

Now for the tricky part. :-)

Surely case #3 should work, because adding an inner wildcard provides a subtyping relationship, so Optional<SB> is a subtype of Optional<? extends CS>.

That much is true, but these are nested within the Function<> generic type, so the "generics are invariant" rule applies again. Thus,

    Function<..., Optional<StringBuilder>>

is not a subtype of

    Function<..., Optional<? extends CharSequence>>

To get around this, we have to add the outer wildcard as well, so that

    Function<..., Optional<StringBuilder>>

is a subtype of

    Function<..., ? extends Optional<? extends CharSequence>>

So that's what ended up in the signature.

Similar analysis applies to the or() case.

Now awaiting a message from Rémi telling me my explanation is incorrect in 3... 2... 1... :-) :-)

s'marks



[1] http://angelikalanger.com/GenericsFAQ/FAQSections/TypeArguments.html#What%20do%20multilevel%20wildcards%20mean?

[2] https://sourceforge.net/p/streamsupport/tickets/125/#2d90

Reply via email to