Interestingly I had to use
static <T> Predicate<T> instanceOf(Class<? extends T> type)
instead of
static <T> Predicate<? super T> instanceOf(Class<T> type)
Those two are roughly the same, but I had to use the former in order to make the following compile:
Try.of(() -> "ok")
.recover(Case(instanceOf(Error.class), "fixed"))
.get();
Here are the relevant type signatures which are involved:
Try<T> recover(Function<? super Throwable, ? extends T> f) { ... }
static <T, R> Case<T, R> Case(Predicate<? super T> predicate, R retVal) { ... }
interface Case<T, R> extends PartialFunction<T, R> {
}
interface PartialFunction<T, R> extends Function<T, R> {
boolean isApplicable(T t);
}
Throwable x = new Error("error");
// COMPILE ERROR: test(Error) in Predicate cannot be applied to (Throwable)
// v
instanceOf(Error.class).test(x);
// COMPILE ERROR: test(capture<? super Error>) in Predicate cannot be applied to (Throwable)
// v
((Predicate<? super Error>) instanceOf(Error.class)).test(x);
// -- Given: class Match<T> { <R> R of(Case<? super T, ? extends R>... cases) }
// COMPILES FINE!
Match(x).of(
Case(instanceOf(Error.class), "ok"),
Case(instanceOf(CompilerError.class), "huh!?")
);
Match.Case<Error, String> _case1 = Case(instanceOf(Error.class), "ok");
Match.Case<? super Throwable, ? extends String> _case2 = Case(instanceOf(Error.class), "ok");
// COMPILE ERROR: Cannot resolve method 'of(Case<Error, String>)'
Match(x).of(
_case1
);
// COMPILES FILE!
Match(x).of(
_case2
);
I don't see why you need this, or why it should be called
narrow