If I write Foo[_ <: Bar]
or Foo[+T <: Bar]
what does the latter let me do, that I could not do with the former?
Is it just convenience, so that can write def bar: T
rather than def bar: Bar
?
In which context is it useful?
Is it actually accurate to say that there is no variance in java? Can one not model it with <? extends Foo>
and <? super Bar>
?
Is it actually accurate to say that there is no variance in java? Can one not model it with
<? extends Foo>
and<? super Bar>
?
Java is usually said to have use-site variance, as opposed to Scala declaration-site variance (well, really Scala supports both). It is actually more expressive, strictly speaking: you can write more sensible programs, e.g. methods which don't put anything into a List
may be covariant while methods which put but don't look at the contents may be contravariant. With declaration-site variance you instead need to have separate immutable and mutable types.
A well-known symptom of the problem is the signature of Set#contains
in Scala, which can't just accept A
without forcing Set
to be invariant.
The problem with having only use-site variance is that it complicates the signatures of all methods working with the type if you want to be consistent: not just the ones declared on the type itself, but those which call them.
See also How does Java's use-site variance compare to C#'s declaration site variance? and https://kotlinlang.org/docs/reference/generics.html#variance.