I know that Java\'s type system is unsound (it fails to type check constructs that are semantically legal) and undecidable (it fails to type check some construct).
For i
Of course the answer of @Eric-Lippert is authoritative. I would just like to stress though that the Variance Problem above applies only to Arrays.
It goes away when using Generics, because then you can have only Co-, Contra- or In-Variance. This disallows one of these applications: either Member Assignment, Member Queries or Collection Assignment:
InVariance disallows Collection Assignment:
IList giraffes3 = new List{new()};
IList animals3 = giraffes3; // ! does NOT compile!
Co-Variance disallows Member Assignment:
IReadOnlyList giraffes1 = new List{new()};
IReadOnlyList animals1 = giraffes1; // This is legal!
animals1[0] = new Tiger(); // ! does NOT compile!
Contra-Variance disallows passing other Subtypes:
IObserver animals2 = new MyObserver();
IObserver giraffes2 = animals2; // This is legal!
giraffes2.OnNext(new Giraffe());
animals2.OnNext(new Tiger());
giraffes2.OnNext(new Tiger()); // ! does NOT compile!
Full Variance allows everything but fails at Runtime (which is the worst):
Giraffe[] giraffes = {new()};
Animal[] animals = giraffes; // This is legal!
animals[0] = new Tiger(); // ! Runtime Exception !
So as long as you try to avoid using arrays in APIs and use them only internally e.g. for performance, you should be quite fine.