Scott Boring
Scott Boring

Reputation: 2781

Polymorphism and subtypes for Flow arrays

I can't get polymorphic subtypes to work in arrays with Flow generics as I would in another language like Java.

Consider the following.

interface Person {
    name:string;
}

class Employee implements Person {
    name:string;
    badge:string;
}

interface Workplace {
    people:Array<Person>;
}

class MyOffice implements Workplace {
    people:Array<Employee>;  // ERROR: Incompatible with Workplace.people
}

This would fail in Java as well; but Java has a way to implement this correctly by indicating the people array in Workplace would contain subtypes of Person.

interface Workplace {
    people:Array<? extends Person>; // PSUEDO CODE: This is how Java supports subtypes
}

I have not been able to find a comparable mechanism in Flow. Flow discusses variance here: https://flow.org/en/docs/lang/variance/#toc-covariance and https://flow.org/en/docs/lang/depth-subtyping/

Which suggests that the following should work.

interface Workplace {
    people:Array<+Person>;
}

But this syntax fails.

Is there a way in Flow to declare an Array covariant type?

Upvotes: 1

Views: 136

Answers (1)

loganfsmyth
loganfsmyth

Reputation: 161677

Variance in Flow takes some getting used to. The core thing, as you've mentioned, is that these two operations would be invalid if

interface Workplace {
    people:Array<Person>;
}

were allowed as-is:

var workplace: Workplace = new MyOffice();

// Not an `Employee`, can't allow adding to array
workplace.people.push(new SomeOtherPersonImpl()); 

// Not an `Employee`, can't allow replacing array.
workplace.people = [new SomeOtherPersonImpl()];

to get both of these properties, we need to

  1. Make the people array read-only ($ReadOnlyArray).
  2. Make the people property read-only. (The + you mentioned)

Combining these, you end up with:

interface Workplace {
    +people: $ReadOnlyArray<Person>;
}

(Flow Try Example)

Upvotes: 3

Related Questions