I'm working on a functional programming library for Java, and I've hit a frustrating issue. I've got the following functions in my Option<V>
class:
/**
* Returns an Option containing the provided value.
*/
public static <V> Option<V> some(V value)
{...}
/**
* Returns an Option that contains nothing.
*/
public static <V> Option<V> none()
{...}
/**
* Decide control flow based on whether this is Some or None,
* returning the result of the chosen operation.
*
* @param some the operation to perform on the contained value if there is one
* @param none the operation to perform if there is no contained value
* @return the result of the matched operation
*/
public <T> T matchThen(Function<? super V, ? extends T> some, Supplier<? extends T> none)
{...}
I'm currently implementing a method, orElse
, that uses the methods above, and is implemented like so:
/**
* Returns this if it is a Some, otherwise computes an Option from the given Supplier.
* @param supp the supplier to compute the other Option
* @return the first present value or None
*/
public Option<V> orElse(Supplier<? extends Option<? extends V>> supp)
{
return matchThen(
Option::some, // if there is a value, wrap it back up and return it
supp::get // if there isn't a value, get one from the supplier
);
}
IDEA reports an error with the use of Option::some
in orElse
:
Bad return type in method reference: cannot convert
Option<V>
to? extends Option<? extends V>
My understanding of wildcard captures was that Option<? extends V>
accepts any object of type Option<T>
where <T extends V>
, which would mean that an Option<V>
is definitely an Option<? extends V>
. Likewise, I'd expect that a ? extends Option<? extends V>
type parameter would accept the same thing (an Option<T>
as above or an Option<V>
).
So, I have two questions:
- Why is this error occurring? I've come to expect this to be the case where
? extends Type<? extends V>
works. Is my expectation being misapplied in this case? I can see how I could be misreading the error, as there's a few types involved, and I'll admit I'm not certain my above analysis is correct. - Is there a fix to the method signatures that doesn't sacrifice flexibility, or does so minimally? I'd love for users of this library to not have to worry about actually-compatible values and functions raising type errors because of my API.
Note
I'm not asking for an implementation of orElse
that avoids this type error; I have a tool for that already, and I don't care too much if my implementation uses minor workarounds. My main concern is that users of this library may face this type of issue when implementing their own solutions, so I want to make these methods as flexible type-wise as I can, which is why I have all these wildcards in the first place.