Doesn't work, as Stuart has noted (s'marks, as far as I know your explanation is 100% correct). Nested generics == pain :-(
Regards, Michael On Fri, Oct 7, 2016 at 4:40 PM, Stefan Zobel <splitera...@gmail.com> wrote: > 2016-10-07 21:22 GMT+02:00 Stuart Marks <stuart.ma...@oracle.com>: > > > > > > 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 > > > > > > Hhm, that's really mind-boggling! > > What's wrong with the alternative "additional bounded type parameter" > approach? > > Couldn't we also get by with something like > > <V, U extends V> Optional<V> flatMap(Function<? super T, Optional<U>> > mapper) > > > and > > > <S extends T> Optional<T> or(Supplier<Optional<S>> supplier) > > > Personally, I find that much easier to digest. But that's only me, of > course. > > > Regards, > Stefan >