contravariance confusion resolved

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
3 messages Options
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

contravariance confusion resolved

kshaw
I think I finally understand why Function1 trait has a contravariant type parameter, after not understanding several explanations. I thought I would share what I was being confused about in case it is interesting to anyone or in case I demonstrate that I didn't actually understand.

Here is an example from programming in scala:

 class Publication(val title: String)
  class Book(title: Stringextends Publication(title)

  object Library {
   val books: Set[Book] =
     Set(
       new Book("Programming in Scala"),
       new Book("Walden")
     )
   def printBookList(info: Book => AnyRef) = {
     for (book <- books) println(info(book))
   }
  }

  object Customer extends App {
   def getTitle(p: Publication): String = p.title
   Library.printBookList(getTitle)
  }

Part of the explanation is:

Because any method declared in Publication is also available on its subclass Book, everything should work, which is what contravariance of function parameter types means

Each time I read an explanation like this, I was baffled, because I thought that it is demonstrating the opposite, that a parameter declared as Publication can be set from a sub-class of Publication.

I think it would be easier for people to understand if the explanation showed that the fact that the type parameter allows a super-class to be supplied means that the implementation accepts instances of a subclass of it's parameter's type and that there is potential confusion because variance in opposite directions is being described.
 

--
You received this message because you are subscribed to the Google Groups "scala-user" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email].
For more options, visit https://groups.google.com/d/optout.
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: contravariance confusion resolved

oss.mlists
You might be looking at it from a wrong angle and it causes the confusion. You have to look at it from the point of the public API and what you provide to it. In this case the public API is printBookList(info: Book => AnyRef). The point of subtyping is to be able to substitute types and variance further unlocks more options which types can be plugged into this public API. Without variance only Book => AnyRef functions could be used in printBookList method.

You can vary input parameter type for info function towards its super types, you can use type Publication => AnyRef instead of Book => AnyRef and it is a contravariant direction in its input parameter. It will work because it is guaranteed your getTitle function which takes Publication type will be provided with a type which has all methods which info function can potentially use. For sure it will be Book but it can be BetterBook or EvenBetterBook (note, that I think here you start to think about covariance and get confused because BetterBook would be a subtype of Book).

If you would write function getTitle(b: BetterBook): AnyRef, than you would try to replace Book type in printBookList method with BetterBook which is subtype of Book and this is a covariant direction. It wouldn't work because getTitle could potentially use a method from BetterBook which is possibly not present on Book. And printBookList doesn't guarantee it will provide BetterBook, it can but doesn't have to. It only guarantees that Book or its supertype is provided.

What I think you confuse is how it varies what you get into getTitle with what you give to printBookList. What you can give to printBookList is what variance talks about.

Covariance for info return type works similarily but in an opposite direction.

Hopefully I haven't confused you even more,
Petr


--
You received this message because you are subscribed to the Google Groups "scala-user" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email].
For more options, visit https://groups.google.com/d/optout.
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: contravariance confusion resolved

oss.mlists
Just to complete covariance for return type. Now printBookList consumes output of your getTitle and its body is written against AnyRef type. It means that if your function will provide any subtype of AnyRef it is guaranteed printBookList will work with it because it can be implicitely casted to AnyRef. Hence you can freely vary getTitle return type in a covariance direction.

Petr

--
You received this message because you are subscribed to the Google Groups "scala-user" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email].
For more options, visit https://groups.google.com/d/optout.
Loading...