

Join them; it only takes a minute:

Sign up
Join the Stack Overflow community to:
  1. Ask programming questions
  2. Answer and help your peers
  3. Get recognized for your expertise

I am thinking of the following example to illustrate why contravariance is useful.

Let's consider a GUI framework with Widgets, Events, and Event Listeners.

abstract class Event;
class KeyEvent extends Event
class MouseEvent extends Event

trait EventListener[-E] { def listen(e:E) }

Let Widgets define the following methods:

def addKeyEventListener(listener:EventListener[KeyEvent])
def addMouseEventListener(listener:EventListener[MouseEvent])

These methods accept only "specific" event listeners, which is fine. However I would like to define also "kitchen-sink" listeners, which listen to all events, and pass such listeners to the "add listener" methods above.

For instance, I would like to define LogEventListener to log all incoming events

class LogEventListener extends EventListener[Event] {
   def listen(e:Event) { log(event) }

Since the trait EventListener is contravariant in Event we can pass LogEventListener to all those "add listener" methods without losing their type safety.

Does it make sense ?

share|improve this question
+1 good question, bad accept-rate. sad! – Nishant Mar 18 '11 at 14:04

It makes sense to me, anyway. And it is also one of the most intuitive examples I have seen: something which listens to all events naturally will listen to key events or mouse events.

share|improve this answer

Makes sense to me too. As a rule of thumb, a parametrized type Type[A] should be contravariant with respect to its type parameter A each time it is meant to accept instances of A to do something with them by means of accepting them as parameters.

For instance, the Java type Comparator[T], if it had been defined in Scala, would have been contravariant: a Comparator[Any] should be a subtype of Comparator[String], as it can compare all objects a Comparator[String] can compare, and more. The most general example is the argument types of the FunctionX classes, which are all contravariant.

share|improve this answer

Your Answer


