RFR(s): 8152617 add missing wildcards to Optional or() and flatMap()

Michael Nascimento misterm at gmail.com
Fri Oct 7 19:42:07 UTC 2016


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 <spliterator at gmail.com> wrote:

> 2016-10-07 21:22 GMT+02:00 Stuart Marks <stuart.marks at 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
>


More information about the core-libs-dev mailing list