Description
Bug Report
π Search Terms
contravariance bypass inheritance variance annotation
π Version & Regression Information
- This is the behavior in every version I tried, and I reviewed the FAQ for entries about variance.
β― Playground Link
Playground link with relevant code
π» Code
In this example we use contravariance to make Comparator<Animal>
assignable to Comparator<Dog>
: something than can compare animals can compare dogs.
class Animal { }
class Dog extends Animal {
wouf = true;
}
class Comparator<in T> {
public compare(a: T, b: T): boolean {
return true;
}
}
class DogComparator extends Comparator<Dog> {
compareDogs = true;
}
// [ok] an Animal comparator can compare Dogs, so then it is assignable to Comparator<Dog>
const okCompareDogs: Comparator<Dog> = new Comparator<Animal>();
// [error as expected] a Dog comparator cannot compare Animals as it may require specific props of Dog for comparison
const okCompareAnimals: Comparator<Animal> = new Comparator<Dog>();
// [should be an error] It should be the same here, the fact that DogComparator is a subclass of Comparator<Dog> should not bypass contravariance
// DogComparator which extends Comparator<Dog> is still not a subclass of Comparator<Animal> as Animal is not a subclass of Dog
const nokCompareAnimals: Comparator<Animal> = new DogComparator();
π Actual behavior
The following line is accepted by the compiler:
const nokCompareAnimals: Comparator<Animal> = new DogComparator();
I think the problem is that as DogComparator
is a subclass of Comparator
, the compiler only checks for
(a: Dog, b: Dog) => boolean
to be assignable to (a: Animal, b: Animal) => void
, regardless of contravariance annotation put on the generic type.
π Expected behavior
The nok line above should give a compilation error as contravariance on Comparator
's generic parameter should prevent DogComparator
(which extends Comparator<Dog>
) from being treated as a Comparator<Animal>
.
Even if (a: Dog, b: Dog) => boolean
is assignable to (a: Animal, b: Animal) => void
, there should be a second contraint to check if Animal
is a subtype of Dog
(which will give the error) because of contravariance on the generic parameter.
For information this is the case in Kotlin: see this playground sample
Thanks π