TL;DR
The answer to your question is related to Java's type inference in conjunction with type variance (covariance in our case). It has nothing to do with Vavr in particular.
Try<List<Integer>>
is a subtype of Try<? extends Seq<? extends Number>>
.
- But
Try<List<Integer>>
is not a subtype of Try<Seq<? extends Number>>
.
Change the return type of the lol()
method(s) to the Try<? extends Seq<? extends Number>>
and all will compile fine.
Let us take a detailed look.
public Try<Seq<? extends Number>> lol() { // line 1
return Try.of(() -> List.of(1, 2, 3)) // line 2
//.onFailure(Object::hashCode) // line 3
;
}
The lol()
method does return a value of type Try<Seq<? extends Number>>
(see line 1).
The return statement in line 2 returns an instance of Try
that is constructed using the factory method Try.of(...)
. In Vavr 0.9.x, it is defined the following way:
static <T> Try<T> of(CheckedFunction0<? extends T> supplier) {
// implementation omitted
}
The compiler infers:
// type T = Seq<? extends Number>
Try.of(() -> List.of(1, 2, 3))
because it needs to match both, the return type of the method lol()
and the CheckedFunction0
signature of the factory method Try.of
.
This compiles fine, because the supplier
function returns a value of type ? extends T
, which is ? extends Seq<? extends Number>
, which is compatible with the actual return type List<Integer>
(see TL;DR section above).
If we now uncomment the .onFailure
part (line 3), then the generic type argument T
of the factory method Try.of
does not have the scope of the return type of lol()
anymore. The compiler infers T
to be List<Integer>
because it always tries to find the most specific type that is applicable.
.onFailure
returns a value of the type List<Integer>
because it returns exactly the same type if its instance. But Try<List<Integer>>
is not a subtype of Try<Seq<? extends Number>>
(see TL;DR section above), so the code does not compile anymore.
Making the lol()
method covariant in its return type will satisfy the compiler:
// before: Try<Seq<? extends Number>>
Try<? extends Seq<? extends Number>> lol() { // line 1
return Try.of(() -> List.of(1, 2, 3)) // line 2
.onFailure(Object::hashCode); // line 3
}
Btw, to define the correct generic variance throughout the type hierarchy of Vavr, especially for the collections, was one of the hard parts when creating Vavr. Java's type system is not perfect, there are still several things we can't express with Java's generics. See also my blog post "Declaration-Site Variance in a Future Java"
Disclaimer: I'm the creator of Vavr (formerly Javaslang)