Here is a simplified excerpt from a Java promise API that I’m using from Kotlin. Only signatures matter.
import java.util.Arrays;
import java.util.Collection;
import java.util.function.Function;
import java.util.stream.Collectors;
public class MyFuture<T> {
private T value;
private Throwable error;
private MyFuture(T value, Throwable error) {
this.value = value;
this.error = error;
}
public static <T> MyFuture<T> value(T value) {
return new MyFuture<T>(value, null);
}
public static <T> MyFuture<T> error(Throwable error) {
return new MyFuture<T>(null, error);
}
public T getValue() {
return value;
}
public Throwable getError() {
return error;
}
<U> MyFuture<U> andThen(Function<? super T, MyFuture<U>> callback) {
return callback.apply(value);
}
@SafeVarargs
public static <T> MyFuture<Collection<T>> allOf(MyFuture<T>... futures) {
return MyFuture.value(Arrays.asList(futures).stream().map(MyFuture::getValue).collect(Collectors.toList()));
}
}
Here is a sample usage from Java code:
public class JavaClient {
public static void main(String[] args) {
MyFuture.allOf(MyFuture.value(42), MyFuture.value("other"));
MyFuture<String> x = MyFuture.value("foo").andThen(str -> MyFuture.error(new RuntimeException("ouch")));
}
}
Here is the best Kotlin translation I could come up with:
fun main(args: Array<String>) {
// extra casts required, give bogus warning "this cast can never succeed"
MyFuture.allOf(
MyFuture.value(42) as MyFuture<Any>,
MyFuture.value("other") as MyFuture<Any>
)
val x: MyFuture<String> = MyFuture.value("foo").andThen {
// extra <String> required (which doesn't make much sense for an error, from an API user's perspective)
// otherwise "not enough information to infer parameter T"
MyFuture.error<String>(RuntimeException("ouch"))
}
}
Are these known limitations of Java interop?