Я думаю о следующем примере, чтобы проиллюстрировать, почему контравариантность полезна.
Рассмотрим схему GUI с Widgets, Events и Event Listeners.
abstract class Event;
class KeyEvent extends Event
class MouseEvent extends Event
trait EventListener[-E] { def listen(e:E) }
Пусть Widgets определяют следующие методы:
def addKeyEventListener(listener:EventListener[KeyEvent])
def addMouseEventListener(listener:EventListener[MouseEvent])
Эти методы принимают только "конкретные" прослушиватели событий, и это нормально. Однако я хотел бы также определить слушателей "кухонного раковины", которые слушали все события и передавали таких слушателей методам "добавить слушателя" выше.
Например, я хотел бы определить LogEventListener для регистрации всех входящих событий
class LogEventListener extends EventListener[Event] {
def listen(e:Event) { log(event) }
}
Так как признак EventListener является контравариантным в Event, мы можем передать LogEventListener всем этим методам "add listener", не теряя при этом своей безопасности типов.
Имеет ли смысл?