RFR(s): 8152617 add missing wildcards to Optional or() and flatMap()
Stefan Zobel
spliterator at gmail.com
Fri Oct 7 19:40:16 UTC 2016
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