Structural Type Dispatch in Scala - scala

I'm trying to get a better grasp of structural type dispatch. For instance, assume I have an iterable object with a summary method that computes the mean. So o.summary() gives the mean value of the list. I might like to use structural type dispatch to enable summary(o).
Is there a set of best practices regarding o.summary() vs. summary(o)?
How does scala resolve summary(o) if I have a method summary(o: ObjectType) and summary(o: { def summary: Double})
How does structural type dispatch differ from multimethods or generic functions?
Michael Galpin gives the following discription about structural type dispatch:
Structural types are Scala’s version of “responds-to” style programming as seen in many dynamic languages. So like
def sayName ( x : { def name:String }){
println(x.name)
}
Then any object with a method called name that takes no parameters and returns a string, can be passed to sayName:
case class Person(name:String)
val dean = Person("Dean")
sayName(dean) // Dean

-- 1. In your example, I wouldn't use the summary(o) version, as this is not a very object oriented style of programming. When calling o.summary (you could drop the brackets as it has no side-effects), you are asking for the summary property of o. When calling summary(o), you are passing o to a method that calculates the summary of o. I believe that the first approach is nicer :).
I haven't used structural type dispatch much, but I assume that it is best suited (in a large system) for the case where you would have to write an interface just because one method wants a type that has some method defined. Sometimes creating that interface and forcing the clients to implement it can be awkward. Sometimes you want to use a client defined in another API which conforms to your interface but doesn't explicitly implement it. So, in my opinion, structural type dispatch serves as a nice way to make the adapter pattern implicitly (saves on boilerplate, yay!).
-- 2. Apparently if you call summary(o) and o is of ObjectType, summary(o: ObjectType) gets called (which does make sense). If you call summary(bar), in which bar is not of ObjectType, two things can happen. The call compiles if bar has the method summary() of the right signature and name or otherwise, the call doesn't compile.
Example:
scala> case class ObjectType(summary: Double)
defined class ObjectType
scala> val o = ObjectType(1.2)
o: ObjectType = ObjectType(1.2)
scala> object Test {
| def summary(o: ObjectType) { println("1") }
| def summary(o: { def summary: Double}) { println("2")}
| }
defined module Test
scala> Test.summary(o)
1
Unfortunately, something like the following does not compile due to type erasure:
scala> object Test{
| def foo(a: {def a: Int}) { println("A") }
| def foo(b: {def b: Int}) { println("B") }
| }
:6: error: double definition:
method foo:(AnyRef{def b(): Int})Unit and
method foo:(AnyRef{def a(): Int})Unit at line 5
have same type after erasure: (java.lang.Object)Unit
def foo(b: {def b: Int}) { println("B") }
-- 3. In a sense, structural type dispatch is more dynamic than generic methods, and also serves a different purpose. In a generic method you can say either: a. I want something of any type; b. I want something of a type that is a subtype of A; c. I'll take something that is a supertype of B; d. I'll take something that has an implicit conversion to type C. All of these are much stricter than just "I want a type that has the method foo with the right signature". Also, structural type dispatch does use reflection, as they are implemented by type erasure.
I don't know much about multimethods, but looking at the wikipedia article, it seems that multimethods in Scala can be achieved using pattern matching. Example:
def collide(a: Collider, b: Collider) = (a, b) match {
case (asteroid: Asteroid, spaceship: Spaceship) => // ...
case (asteroid1: Asteroid, asteroid2: Asteroid) => // ...
...
Again, you could use structural type dispatch - def collide(a: {def processCollision()}), but that depends on a design decision (and I would create an interface in this example).
-- Flaviu Cipcigan

Structural data types aren't really all that useful. That's not to say they are useless, but they definitely a niche thing.
For instance, you might want to write a generic test case for the "size" of something. You might do it like this:
def hasSize(o: { def size: Int }, s: Int): Boolean = {
o.size == s
}
This can then be used with any object that implements the "size" method, no matter its class hierarchy.
Now, they are NOT structural type dispatches. They are NOT related to dispatching, but to type definition.
And Scala is an object oriented language always. You must call methods on objects. Function calls are actually "apply" method calls. Things like "println" are just members of objects imported into scope.

I think you asked what Scala does with a call on a structural type. It uses reflection. For example, consider
def repeat(x: { def quack(): Unit }, n: Int) {
for (i <- 1 to n) x.quack()
}
The call x.quack() is compiled into a lookup of the quack method, and then a call, both using Java reflection. (You can verify that by looking at the byte codes with javap. Look for a class with a funny name like Example$$anonfun$repeat$1.)
If you think about it, it's not surprising. There is no way of making a regular method call because there is no common interface or superclass.
So, the other respondents were absolutely right that you don't want to do this unless you must. The cost is very high.

Related

Understanding Scala Implicits

While reading Functional Programming in Scala by Chiusano and Bjarnason, I encountered the following code in chapter 9, Parser Combinators:
trait Parsers[ParseError, Parser[+_]] { self =>
...
def or[A](s1: Parser[A], s2: Parser[A]): Parser[A]
implicit def string(s: String): Parser[String]
implicit def operators[A](p: Parser[A]) = ParserOps[A](p)
implicit def asStringParser[A](a: A)(implicit f: A => Parser[String]):
ParserOps[String] = ParserOps(f(a))
case class ParserOps[A](p: Parser[A]) {
def |[B>:A](p2: Parser[B]): Parser[B] = self.or(p,p2)
def or[B>:A](p2: => Parser[B]): Parser[B] = self.or(p,p2)
}
}
I understand that if there is a type incompatibility or missing parameters during compilation, the Scala compiler would look for a missing function that converts the non-matching type to the desired type or a variable in scope with the desired type that fits the missing parameter respectively.
If a string occurs in a place that requires a Parser[String], the string function in the above trait should be invoked to convert the string to a Parser[String].
However, I've difficulties understanding the operators and asStringParser functions. These are the questions that I have:
For the implicit operators function, why isn't there a return type?
Why is ParserOps defined as a case class and why can't the | or or function be defined in the Parsers trait itself?
What exactly is the asStringParser trying to accomplish? What is its purpose here?
Why is self needed? The book says, "Use self to explicitly disambiguate reference to the or method on the trait," but what does it mean?
I'm truly enjoying the book but the use of advanced language-specific constructs in this chapter is hindering my progress. It would be of great help if you can explain to me how this code works. I understand that the goal is to make the library "nicer" to use through operators like | and or, but don't understand how this is done.
Every method has a return type. In this case, it's ParserOps[A]. You don't have to write it out explicitly, because in this case it can be inferred automatically.
Probably because of the automatically provided ParserOps.apply-factory method in the companion object. You need fewer vals in the constructor, and you don't need the new keyword to instantiate ParserOps. It is not used in pattern matching though, so, you could do the same thing with an ordinary (non-case) class, wouldn't matter.
It's the "pimp-my-library"-pattern. It attaches methods | and or to Parser, without forcing Parser to inherit from anything. In this way, you can later declare Parser to be something like ParserState => Result[A], but you will still have methods | and or available (even though Function1[ParserState, Result[A]] does not have them).
You could put | and or directly in Parsers, but then you would have to use the syntax
|(a, b)
or(a, b)
instead of the much nicer
a | b
a or b
There are no "real operators" in Scala, everything is a method. If you want to implement a method that behaves as if it were an infix operator, you do exactly what is done in the book.

Why does Scala not have a return/unit function defined for each monad (in contrast to Haskell)?

What is the reason behind the design decision in Scala that monads do not have a return/unit function in contrast to Haskell where each monad has a return function that puts a value into a standard monadic context for the given monad?
For example why List, Option, Set etc... do not have a return/unit functions defined in the standard library as shown in the slides below?
I am asking this because in the reactive Coursera course Martin Odersky explicitly mentioned this fact, as can be seen below in the slides, but did not explain why Scala does not have them even though unit/return is an essential property of a monad.
As Ørjan Johansen said, Scala does not support method dispatching on return type. Scala object system is built over JVM one, and JVM invokevirtual instruction, which is the main tool for dynamic polymorphism, dispatches the call based on type of this object.
As a side note, dispatching is a process of selecting concrete method to call. In Scala/Java all methods are virtual, that is, the actual method which is called depends on actual type of the object.
class A { def hello() = println("hello method in A") }
class B extends A { override def hello() = println("hello method in B") }
val x: A = new A
x.hello() // prints "hello method in A"
val y: A = new B
y.hello() // prints "hello method in B"
Here, even if y variable is of type A, hello method from B is called, because JVM "sees" that the actual type of the object in y is B and invokes appropriate method.
However, JVM only takes the type of the variable on which the method is called into account. It is impossible, for example, to call different methods based on runtime type of arguments without explicit checks. For example:
class A {
def hello(x: Number) = println(s"Number: $x")
def hello(y: Int) = println(s"Integer: $y")
}
val a = new A
val n: Number = 10: Int
a.hello(n) // prints "Number: 10"
Here we have two methods with the same name, but with different parameter type. And even if ns actual type is Int, hello(Number) version is called - it is resolved statically based on n static variable type (this feature, static resolution based on argument types, is called overloading). Hence, there is no dynamic dispatch on method arguments. Some languages support dispatching on method arguments too, for example, Common Lisp's CLOS or Clojure's multimethods work like that.
Haskell has advanced type system (it is comparable to Scala's and in fact they both originate in System F, but Scala type system supports subtyping which makes type inference much more difficult) which allows global type inference, at least, without certain extensions enabled. Haskell also has a concept of type classes, which is its tool for dynamic polymorphism. Type classes can be loosely thought of as interfaces without inheritance but with dispatch on parameter and return value types. For example, this is a valid type class:
class Read a where
read :: String -> a
instance Read Integer where
read s = -- parse a string into an integer
instance Read Double where
read s = -- parse a string into a double
Then, depending on the context where method is called, read function for Integer or Double can be called:
x :: Integer
x = read "12345" // read for Integer is called
y :: Double
y = read "12345.0" // read for Double is called
This is a very powerful technique which has no correspondence in bare JVM object system, so Scala object system does not support it too. Also the lack of full-scale type inference would make this feature somewhat cumbersome to use. So, Scala standard library does not have return/unit method anywhere - it is impossible to express it using regular object system, there is simply no place where such a method could be defined. Consequently, monad concept in Scala is implicit and conventional - everything with appropriate flatMap method can be considered a monad, and everything with the right methods can be used in for construction. This is much like duck typing.
However, Scala type system together with its implicits mechanism is powerful enough to express full-featured type classes, and, by extension, generic monads in formal way, though due to difficulties in full type inference it may require adding more type annotations than in Haskell.
This is definition of monad type class in Scala:
trait Monad[M[_]] {
def unit[A](a: A): M[A]
def bind[A, B](ma: M[A])(f: A => M[B]): M[B]
}
And this is its implementation for Option:
implicit object OptionMonad extends Monad[Option] {
def unit[A](a: A) = Some(a)
def bind[A, B](ma: Option[A])(f: A => Option[B]): Option[B] =
ma.flatMap(f)
}
Then this can be used in generic way like this:
// note M[_]: Monad context bound
// this is a port of Haskell's filterM found here:
// http://hackage.haskell.org/package/base-4.7.0.1/docs/src/Control-Monad.html#filterM
def filterM[M[_]: Monad, A](as: Seq[A])(f: A => M[Boolean]): M[Seq[A]] = {
val m = implicitly[Monad[M]]
as match {
case x +: xs =>
m.bind(f(x)) { flg =>
m.bind(filterM(xs)(f)) { ys =>
m.unit(if (flg) x +: ys else ys)
}
}
case _ => m.unit(Seq.empty[A])
}
}
// using it
def run(s: Seq[Int]) = {
import whatever.OptionMonad // bring type class instance into scope
// leave all even numbers in the list, but fail if the list contains 13
filterM[Option, Int](s) { a =>
if (a == 13) None
else if (a % 2 == 0) Some(true)
else Some(false)
}
}
run(1 to 16) // returns None
run(16 to 32) // returns Some(List(16, 18, 20, 22, 24, 26, 28, 30, 32))
Here filterM is written generically, for any instance of Monad type class. Because OptionMonad implicit object is present at filterM call site, it will be passed to filterM implicitly, and it will be able to make use of its methods.
You can see from above that type classes allow to emulate dispatching on return type even in Scala. In fact, this is exactly what Haskell does under the covers - both Scala and Haskell are passing a dictionary of methods implementing some type class, though in Scala it is somewhat more explicit because these "dictionaries" are first-class objects there and can be imported on demand or even passed explicitly, so it is not really a proper dispatching as it is not that embedded.
If you need this amount of genericity, you can use Scalaz library which contains a lot of type classes (including monad) and their instances for some common types, including Option.
I don't think you're really saying that Scala's monads don't have a unit function - it's rather just that the name of the unit function can vary. That's what seems to be shown in the second slide's examples.
As for why that is so, I think it's just because Scala runs on the JVM, and those function have to be implemented as JVM methods - which are uniquely identified by:
the class they belong to;
their name;
their parameters types.
But they are not identified by their return type. Since the parameter type generally won't differentiate the various unit functions (it's usually just a generic type), you need different names for them.
In practice, they will often be implemented as the apply(x) method on the companion object of the monad class. For example, for the class List, the unit function is the apply(x) method on the object List. By convention, List.apply(x) can be called as List(x) too, which is more common/idiomatic.
So I guess that Scala at least has a naming convention for the unit function, though it doesn't have a unique name for it :
// Some monad :
class M[T] {
def flatMap[U](f: T => M[U]): M[U] = ???
}
// Companion object :
object M {
def apply(x: T): M[T] = ??? // Unit function
}
// Usage of the unit function :
val x = ???
val m = M(x)
Caveat: I'm still learning Haskell and I'm sort of making up this answer as I go.
First, what you already know - that Haskell's do notation desugars to bind:
Borrowing this example from Wikipedia:
add mx my = do
x <- mx
y <- my
return (x + y)
add mx my =
mx >>= (\x ->
my >>= (\y ->
return (x + y)))
Scala's analogue to do is the for-yield expression. It similarly desugars each step to flatMap (its equivalent of bind).
There's a difference, though: The last <- in a for-yield desugars to map, not to flatMap.
def add(mx: Option[Int], my: Option[Int]) =
for {
x <- mx
y <- my
} yield x + y
def add(mx: Option[Int], my: Option[Int]) =
mx.flatMap(x =>
my.map(y =>
x + y))
So because you don't have the "flattening" on the last step, the expression value already has the monad type, so there's no need to "re-wrap" it with something comparable to return.
Actually there is a return function in scala. It is just hard to find.
Scala slightly differs from Haskell in many aspects. Most of that differences are direct consequences of JVM limitations. JVM can not dispatch methods basing on its return type. So Scala introduced type class polymorphism based on implicit evidence to fix this inconvenience.
It is even used in scala standard collections. You may notice numerous usage of CanBuildFrom and CanBuild implicits used in the scala collection api. See scala.collection.immutable.List for example.
Every time you want to build custom collection you should write realization for this implicits. There are not so many guides for writing one though. I recommend you this guide. It shows why CanBuildFrom is so important for collections and how it is used. In fact that is just another form of the return function and anyone familiar with Haskell monads would understand it's importance clearly.
So you may use custom collection as example monads and write other monads basing on provided tutorial.

Can structural typing work with generics?

I have an interface defined using a structural type like this:
trait Foo {
def collection: {
def apply(a: Int) : String
def values() : collection.Iterable[String]
}
}
}
I wanted to have one of the implementers of this interface do so using a standard mutable HashMap:
class Bar {
val collection: HashMap[Int, String] = HashMap[Int, String]()
}
It compiles, but at runtime I get a NoSuchMethod exception when referring a Bar instance through a Foo typed variable. Dumping out the object's methods via reflection I see that the HashMap's apply method takes an Object due to type erasure, and there's some crazily renamed generated apply method that does take an int. Is there a way to make generics work with structural types? Note in this particular case I was able to solve my problem using an actual trait instead of a structural type and that is overall much cleaner.
Short answer is that the apply method parameter is causing you grief because it requires some implicit conversions of the parameter (Int => Integer). Implicits are resolved at compile time, the NoSuchMethodException is likely a result of these missing implicits.
Attempt to use the values method and it should work since there are no implicits being used.
I've attempted to find a way to make this example work but have had no success so far.

Why does Scala need parameterless in addition to zero-parameter methods?

I understand the difference between zero-parameter and parameterless methods, but what I don't really understand is the language design choice that made parameterless methods necessary.
Disadvantages I can think of:
It's confusing. Every week or two there are questions here or on the Scala mailing list about it.
It's complicated; we also have to distinguish between () => X and => X.
It's ambiguous: does x.toFoo(y) mean what it says, or x.toFoo.apply(y)? (Answer: it depends on what overloads there are x's toFoo method and the overloads on Foo's apply method, but if there's a clash you don't see an error until you try to call it.)
It messes up operator style method calling syntax: there is no symbol to use in place of the arguments, when chaining methods, or at the end to avoid semicolon interference. With zero-arg methods you can use the empty parameter list ().
Currently, you can't have both defined in a class: you get an error saying the method is already defined. They also both convert to a Function0.
Why not just make methods def foo and def foo() exactly the same thing, and allow them to be called with or without parentheses? What are the upsides of how it is?
Currying, That's Why
Daniel did a great job at explaining why parameterless methods are necessary. I'll explain why they are regarded distinctly from zero-parameter methods.
Many people view the distinction between parameterless and zero-parameter functions as some vague form of syntactic sugar. In truth it is purely an artifact of how Scala supports currying (for completeness, see below for a more thorough explanation of what currying is, and why we all like it so much).
Formally, a function may have zero or more parameter lists, with zero or more parameters each.
This means the following are valid: def a, def b(), but also the contrived def c()() and def d(x: Int)()()(y: Int) etc...
A function def foo = ??? has zero parameter lists. A function def bar() = ??? has precisely one parameter list, with zero parameters. Introducing additional rules that conflate the two forms would have undermined currying as a consistent language feature: def a would be equivalent in form to def b() and def c()() both; def d(x: Int)()()(y: Int) would be equivalent to def e()(x: Int)(y: Int)()().
One case where currying is irrelevant is when dealing with Java interop. Java does not support currying, so there's no problem with introducing syntactic sugar for zero-parameter methods like "test".length() (which directly invokes java.lang.String#length()) to also be invoked as "test".length.
A quick explanation of currying
Scala supports a language feature called 'currying', named after mathematician Haskell Curry.
Currying allows you to define functions with several parameter lists, e.g.:
def add(a: Int)(b: Int): Int = a + b
add(2)(3) // 5
This is useful, because you can now define inc in terms of a partial application of add:
def inc: Int => Int = add(1)
inc(2) // 3
Currying is most often seen as a way of introducing control structures via libraries, e.g.:
def repeat(n: Int)(thunk: => Any): Unit = (1 to n) foreach { _ => thunk }
repeat(2) {
println("Hello, world")
}
// Hello, world
// Hello, world
As a recap, see how repeat opens up another opportunity to use currying:
def twice: (=> Any) => Unit = repeat(2)
twice {
println("Hello, world")
}
// ... you get the picture :-)
One nice thing about an issue coming up periodically on the ML is that there are periodic answers.
Who can resist a thread called "What is wrong with us?"
https://groups.google.com/forum/#!topic/scala-debate/h2Rej7LlB2A
From: martin odersky Date: Fri, Mar 2, 2012 at
12:13 PM Subject: Re: [scala-debate] what is wrong with us...
What some people think is "wrong with us" is that we are trying bend
over backwards to make Java idioms work smoothly in Scala. The
principaled thing would have been to say def length() and def length
are different, and, sorry, String is a Java class so you have to write
s.length(), not s.length. We work really hard to paper over it by
admitting automatic conversions from s.length to s.length(). That's
problematic as it is. Generalizing that so that the two are identified
in the type system would be a sure way to doom. How then do you
disambiguate:
type Action = () => () def foo: Action
Is then foo of type Action or ()? What about foo()?
Martin
My favorite bit of paulp fiction from that thread:
On Fri, Mar 2, 2012 at 10:15 AM, Rex Kerr <ich...#gmail.com> wrote:
>This would leave you unable to distinguish between the two with
>structural types, but how often is the case when you desperately
>want to distinguish the two compared to the case where distinguishing
>between the two is a hassle?
/** Note to maintenance programmer: It is important that this method be
* callable by classes which have a 'def foo(): Int' but not by classes which
* merely have a 'def foo: Int'. The correctness of this application depends
* on maintaining this distinction.
*
* Additional note to maintenance programmer: I have moved to zambia.
* There is no forwarding address. You will never find me.
*/
def actOnFoo(...)
So the underlying motivation for the feature is to generate this sort of ML thread.
One more bit of googlology:
On Thu, Apr 1, 2010 at 8:04 PM, Rex Kerr <[hidden email]> wrote: On
Thu, Apr 1, 2010 at 1:00 PM, richard emberson <[hidden email]> wrote:
I assume "def getName: String" is the same as "def getName(): String"
No, actually, they are not. Even though they both call a method
without parameters, one is a "method with zero parameter lists" while
the other is a "method with one empty parameter list". If you want to
be even more perplexed, try def getName()(): String (and create a
class with that signature)!
Scala represents parameters as a list of lists, not just a list, and
List() != List(List())
It's kind of a quirky annoyance, especially since there are so few
distinctions between the two otherwise, and since both can be
automatically turned into the function signature () => String.
True. In fact, any conflation between parameterless methods and
methods with empty parameter lists is entirely due to Java interop.
They should be different but then dealing with Java methods would be
just too painful. Can you imagine having to write str.length() each
time you take the length of a string?
Cheers
First off, () => X and => X has absolutely nothing to do with parameterless methods.
Now, it looks pretty silly to write something like this:
var x() = 5
val y() = 2
x() = x() + y()
Now, if you don't follow what the above has to do with parameterless methods, then you should look up uniform access principle. All of the above are method declarations, and all of them can be replaced by def. That is, assuming you remove their parenthesis.
Besides the convention fact mentioned (side-effect versus non-side-effect), it helps with several cases:
Usefulness of having empty-paren
// short apply syntax
object A {
def apply() = 33
}
object B {
def apply = 33
}
A() // works
B() // does not work
// using in place of a curried function
object C {
def m()() = ()
}
val f: () => () => Unit = C.m
Usefulness of having no-paren
// val <=> def, var <=> two related defs
trait T { def a: Int; def a_=(v: Int): Unit }
trait U { def a(): Int; def a_=(v: Int): Unit }
def tt(t: T): Unit = t.a += 1 // works
def tu(u: U): Unit = u.a += 1 // does not work
// avoiding clutter with apply the other way round
object D {
def a = Vector(1, 2, 3)
def b() = Vector(1, 2, 3)
}
D.a(0) // works
D.b(0) // does not work
// object can stand for no-paren method
trait E
trait F { def f: E }
trait G { def f(): E }
object H extends F {
object f extends E // works
}
object I extends G {
object f extends E // does not work
}
Thus in terms of regularity of the language, it makes sense to have the distinction (especially for the last shown case).
I would say both are possible because you can access mutable state with a parameterless method:
class X(private var x: Int) {
def inc() { x += 1 }
def value = x
}
The method value does not have side effects (it only accesses mutable state). This behavior is explicitly mentioned in Programming in Scala:
Such parameterless methods are quite common in Scala. By contrast, methods defined with empty parentheses, such as def height(): Int, are called empty-paren methods. The recommended convention is to use a parameterless method whenever there are no parameters and the method accesses mutable state only by reading fields of the containing object (in particular, it does not change mutable state).
This convention supports the uniform access principle [...]
To summarize, it is encouraged style in Scala to define methods that take no parameters and have no side effects as parameterless methods, i.e., leaving off the empty parentheses. On the other hand, you should never define a method that has side-effects without parentheses, because then invocations of that method would look like a field selection.

Scala contravariance - real life example

I understand covariance and contravariance in scala. Covariance has many applications in the real world, but I can not think of any for contravariance applications, except the same old examples for Functions.
Can someone shed some light on real world examples of contravariance use?
In my opinion, the two most simple examples after Function are ordering and equality. However, the first is not contra-variant in Scala's standard library, and the second doesn't even exist in it. So, I'm going to use Scalaz equivalents: Order and Equal.
Next, I need some class hierarchy, preferably one which is familiar and, of course, it both concepts above must make sense for it. If Scala had a Number superclass of all numeric types, that would have been perfect. Unfortunately, it has no such thing.
So I'm going to try to make the examples with collections. To make it simple, let's just consider Seq[Int] and List[Int]. It should be clear that List[Int] is a subtype of Seq[Int], ie, List[Int] <: Seq[Int].
So, what can we do with it? First, let's write something that compares two lists:
def smaller(a: List[Int], b: List[Int])(implicit ord: Order[List[Int]]) =
if (ord.order(a,b) == LT) a else b
Now I'm going to write an implicit Order for Seq[Int]:
implicit val seqOrder = new Order[Seq[Int]] {
def order(a: Seq[Int], b: Seq[Int]) =
if (a.size < b.size) LT
else if (b.size < a.size) GT
else EQ
}
With these definitions, I can now do something like this:
scala> smaller(List(1), List(1, 2, 3))
res0: List[Int] = List(1)
Note that I'm asking for an Order[List[Int]], but I'm passing a Order[Seq[Int]]. This means that Order[Seq[Int]] <: Order[List[Int]]. Given that Seq[Int] >: List[Int], this is only possible because of contra-variance.
The next question is: does it make any sense?
Let's consider smaller again. I want to compare two lists of integers. Naturally, anything that compares two lists is acceptable, but what's the logic of something that compares two Seq[Int] being acceptable?
Note in the definition of seqOrder how the things being compared becomes parameters to it. Obviously, a List[Int] can be a parameter to something expecting a Seq[Int]. From that follows that a something that compares Seq[Int] is acceptable in place of something that compares List[Int]: they both can be used with the same parameters.
What about the reverse? Let's say I had a method that only compared :: (list's cons), which, together with Nil, is a subtype of List. I obviously could not use this, because smaller might well receive a Nil to compare. It follows that an Order[::[Int]] cannot be used instead of Order[List[Int]].
Let's proceed to equality, and write a method for it:
def equalLists(a: List[Int], b: List[Int])(implicit eq: Equal[List[Int]]) = eq.equal(a, b)
Because Order extends Equal, I can use it with the same implicit above:
scala> equalLists(List(4, 5, 6), List(1, 2, 3)) // we are comparing lengths!
res3: Boolean = true
The logic here is the same one. Anything that can tell whether two Seq[Int] are the same can, obviously, also tell whether two List[Int] are the same. From that, it follows that Equal[Seq[Int]] <: Equal[List[Int]], which is true because Equal is contra-variant.
This example is from the last project I was working on. Say you have a type-class PrettyPrinter[A] that provides logic for pretty-printing objects of type A. Now if B >: A (i.e. if B is superclass of A) and you know how to pretty-print B (i.e. have an instance of PrettyPrinter[B] available) then you can use the same logic to pretty-print A. In other words, B >: A implies PrettyPrinter[B] <: PrettyPrinter[A]. So you can declare PrettyPrinter[A] contravariant on A.
scala> trait Animal
defined trait Animal
scala> case class Dog(name: String) extends Animal
defined class Dog
scala> trait PrettyPrinter[-A] {
| def pprint(a: A): String
| }
defined trait PrettyPrinter
scala> def pprint[A](a: A)(implicit p: PrettyPrinter[A]) = p.pprint(a)
pprint: [A](a: A)(implicit p: PrettyPrinter[A])String
scala> implicit object AnimalPrettyPrinter extends PrettyPrinter[Animal] {
| def pprint(a: Animal) = "[Animal : %s]" format (a)
| }
defined module AnimalPrettyPrinter
scala> pprint(Dog("Tom"))
res159: String = [Animal : Dog(Tom)]
Some other examples would be Ordering type-class from Scala standard library, Equal, Show (isomorphic to PrettyPrinter above), Resource type-classes from Scalaz etc.
Edit:
As Daniel pointed out, Scala's Ordering isn't contravariant. (I really don't know why.) You may instead consider scalaz.Order which is intended for the same purpose as scala.Ordering but is contravariant on its type parameter.
Addendum:
Supertype-subtype relationship is but one type of relationship that can exist between two types. There can be many such relationships possible. Let's consider two types A and B related with function f: B => A (i.e. an arbitrary relation). Data-type F[_] is said to be a contravariant functor if you can define an operation contramap for it that can lift a function of type B => A to F[A => B].
The following laws need to be satisfied:
x.contramap(identity) == x
x.contramap(f).contramap(g) == x.contramap(f compose g)
All of the data types discussed above (Show, Equal etc.) are contravariant functors. This property lets us do useful things such as the one illustrated below:
Suppose you have a class Candidate defined as:
case class Candidate(name: String, age: Int)
You need an Order[Candidate] which orders candidates by their age. Now you know that there is an Order[Int] instance available. You can obtain an Order[Candidate] instance from that with the contramap operation:
val byAgeOrder: Order[Candidate] =
implicitly[Order[Int]] contramap ((_: Candidate).age)
An example based on a real-world event-driven software system. Such a system is based on broad categories of events, like events related to the functioning of the system (system events), events generated by user actions (user events) and so on.
A possible event hierarchy:
trait Event
trait UserEvent extends Event
trait SystemEvent extends Event
trait ApplicationEvent extends SystemEvent
trait ErrorEvent extends ApplicationEvent
Now the programmers working on the event-driven system need to find a way to register/process the events generated in the system. They will create a trait, Sink, that is used to mark components in need to be notified when an event has been fired.
trait Sink[-In] {
def notify(o: In)
}
As a consequence of marking the type parameter with the - symbol, the Sink type became contravariant.
A possible way to notify interested parties that an event happened is to write a method and to pass it the corresponding event. This method will hypothetically do some processing and then it will take care of notifying the event sink:
def appEventFired(e: ApplicationEvent, s: Sink[ApplicationEvent]): Unit = {
// do some processing related to the event
// notify the event sink
s.notify(e)
}
def errorEventFired(e: ErrorEvent, s: Sink[ErrorEvent]): Unit = {
// do some processing related to the event
// notify the event sink
s.notify(e)
}
A couple of hypothetical Sink implementations.
trait SystemEventSink extends Sink[SystemEvent]
val ses = new SystemEventSink {
override def notify(o: SystemEvent): Unit = ???
}
trait GenericEventSink extends Sink[Event]
val ges = new GenericEventSink {
override def notify(o: Event): Unit = ???
}
The following method calls are accepted by the compiler:
appEventFired(new ApplicationEvent {}, ses)
errorEventFired(new ErrorEvent {}, ges)
appEventFired(new ApplicationEvent {}, ges)
Looking at the series of calls you notice that it is possible to call a method expecting a Sink[ApplicationEvent] with a Sink[SystemEvent] and even with a Sink[Event]. Also, you can call the method expecting a Sink[ErrorEvent] with a Sink[Event].
By replacing invariance with a contravariance constraint, a Sink[SystemEvent] becomes a subtype of Sink[ApplicationEvent]. Therefore, contravariance can also be thought of as a ‘widening’ relationship, since types are ‘widened’ from more specific to more generic.
Conclusion
This example has been described in a series of articles about variance found on my blog
In the end, I think it helps to also understand the theory behind it...
Short answer that might help people who were super confused like me and didn't want to read these long winded examples:
Imagine you have 2 classes Animal, and Cat, which extends Animal. Now, imagine that you have a type Printer[Cat], that contains the functionality for printing Cats. And you have a method like this:
def print(p: Printer[Cat], cat: Cat) = p.print(cat)
but the thing is, that since Cat is an Animal, Printer[Animal] should also be able to print Cats, right?
Well, if Printer[T] were defined like Printer[-T], i.e. contravariant, then we could pass Printer[Animal] to the print function above and use its functionality to print cats.
This is why contravariance exists. Another example, from C#, for example, is the class IComparer which is contravariant as well. Why? Because we should be able to use Animal comparers to compare Cats, too.