-1

I'm using Java with vavr and I have a Function1 that accepts a Seq<Parent> and returns a String. Why won't that class accept Seq<Child>? It seems like something with contravariance/covariance/invariance, but I am having trouble working through why it won't compile. Here is my code:

interface Bar {
    String getFoo();
}   

class Foo implements Bar {
    private String foo;
    private String bar;

    @Override
    public String getFoo() {
        return foo;
    }

    public Foo(String foo, String bar) {
        this.foo = foo;
        this.bar = bar;
    }
}


class Scratch {
    public static void main(String[] args) {
        Function1<Seq<Bar>, String> myFunction = (it) -> "foo";
        Foo obj = new Foo("foo", "bar");
        Foo obj1 = new Foo("hello", "world");
        Seq<Foo> list = List.of(obj, obj1);
        String result = myFunction.apply(list); // IntelliJ says this line is incorrect
    }
}

Instead, I get the error (from IntelliJ):

    apply (io.vavr.collection.Seq<Bar>) in Function1 cannot be applied to (io.vavr.collection.Seq<Foo>).

This simple example seems like it should work just fine. What am I missing and why doesn't it work?

Jon Gunter
  • 1,864
  • 2
  • 15
  • 21

1 Answers1

0

I ended up figuring it out. This can be boiled down to how Vavr handles variance with the Seq interface.

Seqs in Scala are covariant, meaning Seq<Child> is treated like a subclass of Seq<Parent>. Thus, the above problem when translated into Scala works.

class Bar {}
class Foo extends Bar

val foos: Seq[Foo] = Seq(new Foo, new Foo, new Foo);
val bars: Seq[Bar] = foos;

However, it seems the vavr's Seq interface is invariant, meaning Seq<Parent> and Seq<Child> are treated as separate classes. Vavr's Seq has a method called narrow() to make these upcasts work properly. That is how to solve the problem above.

class Scratch {
    public static void main(String[] args) {
        Function1<Seq<Bar>, String> myFunction = (it) -> "foo";
        Foo obj = new Foo("foo", "bar");
        Foo obj1 = new Foo("hello", "world");
        Seq<Foo> list = List.of(obj, obj1);
        String result = myFunction.apply(Seq.narrow(list));
   

Not sure why Vavr is designed this way.

Jon Gunter
  • 1,864
  • 2
  • 15
  • 21