Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Safe workaround for broken contravariant bounds in Java?

Tags:

java

generics

As discussed in Bounding generics with 'super' keyword the Java type system is broken/incomplete when it comes to lower bounds on method generics. Since Optional is now part of the JDK, I'm starting to use it more and the problems that Guava encountered with their Optional are starting to become a pain for me. I came up with a decent work around, but I'm not sure its safe. First, let me setup the example:

public class A {}
public class B extends A {}

I would like to be able to declare a method like:

public class Cache {
   private final Map<String, B> cache;
   public <T super B> Optional<T> find(String s) {
       return Optional<T>.ofNullable(cache.get(s));
   }
}

So that both of the following work:

A a = cache.find("A").orElse(new A())
B b = cache.find("B").orElse(new B())

As a workaround, I have a static utility method as follows:

public static <S, T extends S> Optional<S> convertOptional(Optional<T> optional) {
    return (Optional<S>)optional;
} 

So my final question, is this as type-safe as the 'ideal' code above?

A a = OptionalUtil.<A,B>convertOptional(cache.find("A")).orElse(new A());
like image 891
MattWallace Avatar asked Aug 03 '15 20:08

MattWallace


1 Answers

You're effectively trying to view the Optional<B> returned as an Optional<A> without changing the return type (since you can't use the super). I would just map the identity function.

A a = cache.find("A").map(Function.<A> identity()).orElse(new A());
// or shorter
A a = cache.find("A").<A> map(x -> x).orElse(new A());

I don't see anything wrong with your approach though.

like image 84
Sotirios Delimanolis Avatar answered Sep 19 '22 12:09

Sotirios Delimanolis