Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Example of contravariance

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 ?

like image 407
Michael Avatar asked Mar 18 '11 12:03

Michael


People also ask

What is difference between covariance and contravariance?

In C#, covariance and contravariance enable implicit reference conversion for array types, delegate types, and generic type arguments. Covariance preserves assignment compatibility and contravariance reverses it.

What is covariance and contravariance in physics?

In differential geometry, the components of a vector relative to a basis of the tangent bundle are covariant if they change with the same linear transformation as a change of basis. They are contravariant if they change by the inverse transformation.

Can be declared contravariant?

A type can be declared contravariant in a generic interface or delegate only if it defines the type of a method's parameters and not of a method's return type. In , ref , and out parameters must be invariant, meaning they are neither covariant nor contravariant.

What is covariant C#?

Covariance in C# Covariance enables you to pass a derived type where a base type is expected. Co-variance is like variance of the same kind. The base class and other derived classes are considered to be the same kind of class that adds extra functionalities to the base type.


2 Answers

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.

like image 172
Daniel C. Sobral Avatar answered Oct 21 '22 21:10

Daniel C. Sobral


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.

like image 7
Jean-Philippe Pellet Avatar answered Oct 21 '22 19:10

Jean-Philippe Pellet