
Variance in Java - jxub
https://llorllale.github.io/java-variance/
======
BonesJustice
Java is interesting in that variance is defined at a reference site. Contrast
that to, say, C#, where variance is defined at a type's declaration site.

In C#, a type `Function<in T, out R>` is always contravariant with `T` and
covariant with `R`. An assignment target of `Function<String, Object>` can
always accept a `Function<Object, String>` because the definition of
`Function<,>` says that's okay.

In Java, there is no way to impose variance rules at a type's declaration
site. An assignment target of `Function<String, Object>` can only (barring
unchecked cheats) ever refer to a `Function<String, Object>`. However, I can
declare a reference of `Function<? super String, ? extends Object>`, and
suddenly it can be assigned a `Function<Object, String>`.

I always found this difference interesting. C# is much stricter: all members
of a type with generic variance must obey that variance, or that type will not
compile. The type `List<T>` can only be invariant with `T` because `T` appears
as both an input (e.g., in `Add(T)`) and as an output (e.g., `T this[int]`).
In Java, enforcement happens at the usage site. If I declare a `List<? extends
String>`, the compiler will happily let me call methods for which `T` is an
_output_ (e.g., `get(int)`), but it prohibits me from calling methods for
which `T` is an _input_ (e.g., `add(T)`).

As an interesting consequence of this decision, Java allows for the concept of
'bivariance': it's possible to declare a variable of type `List<?>` in Java
and assign any instantiation of `List<>` to it. Moreover, I can still invoke
members which do not contain `T` in their signature (e.g., I can call `int
size()`). In C#, this is simply not possible. To work around this, some
generic interfaces have non-generic counterparts. For example, every
`IEnumerable<>` instantiation is also an instance of the _non-generic_
`IEnumerable` type.

I am curious which approach is more common across other programming languages.

------
noir_lord
Is there a good general book on type theory as it related to programming
languages or a good place to start?

I don't have a strong comp-sci background even though I've been a professional
programmer for a long time, I've always preferred strongly typed languages
with ADT's just from experience but I'd really like to understand this type of
stuff better.

~~~
kryptiskt
Types and Programming Languages by Benjamin Pierce

[https://www.cis.upenn.edu/~bcpierce/tapl/](https://www.cis.upenn.edu/~bcpierce/tapl/)

~~~
noir_lord
Thank you!, this looks good.

Heh, The kindle edition is only 3 quid less than the dead tree (in the UK).

That one does make me chuckle, Might have to check if the library has a copy
first.

------
brianpgordon
This covers a lot of the same things as my own blog post on the topic:

[https://briangordon.github.io/2014/09/covariance-and-
contrav...](https://briangordon.github.io/2014/09/covariance-and-
contravariance.html)

------
dmitryminkovsky
Great post, this is a tricky subject. I find myself referring to these
diagrams from time to time:
[https://stackoverflow.com/a/33246935/741970](https://stackoverflow.com/a/33246935/741970)

~~~
ben509
That's a good explanation, but I've found it helps to write out examples on
paper and test them by hand.

~~~
dmitryminkovsky
Test them by hand in what sense? If you mean in simple cases on the computer,
then why write them on paper? (I do love writing on paper, just not sure why
here)

~~~
ben509
Test them in the sense of thinking it through by working through the cases,
it's more to help internalize the idea.

And writing things down is forcing my mind to serialize and deserialize ideas,
and I think that helps the process.

(I'm not actually doing this often for Java generics, but I've been working on
some other type theory stuff and I found it helped me get beyond "I understand
this" to "I now feel relatively fluent expressing these ideas.")

~~~
dmitryminkovsky
Oh yeah, for sure. Thanks for clarifying.

------
zeroimpl
I always find the ArrayStoreException funny. I've written a lot of Java code
over the years, including a fair bit pre-generics, and yet I don't believe
I've ever triggered this exception.

