Если бы я назвал самую неприятную вещь в scala, то это было бы для следующего кода:
trait G[+T]
class H[+T] extends G[T]
def f[A<:G[X], X<:Int](g :A)
val g :H[Int]
f(g)
компилятор определяет типы последнего обращения к f [H [Int], Nothing] и жалуется передо мной на свою глупость.
Однако, зная scala, он знает лучше меня. В чем причина этого? Поскольку и G, и H ковариантны относительно T, S <: G[X] with H[_] <=> S<: H[X]
для любого типа S. Этот единственный недостаток заставил меня спроектировать все вокруг, избегая необходимости явно указывать типы - здесь это может выглядеть как ничто, но когда имена становятся `` реальной '' длины и практически любой метод является универсальным, и часто, работая с двумя универсальными типами, оказывается, что большая часть кода является объявлениями типов.
РЕДАКТИРОВАТЬ: вышеупомянутый случай был решен ниже Ноа, но что, когда производный класс не того же типа, что и базовый класс, как показано ниже?
trait G[+X]
class H[+X, Y] extends G[X]
class F extends G[Int]
def f[A<:G[X], X<:Int](g :A) = g
val h: H[Int, String] = ???
val g :F = ???
f(g)
f(h)