views:

140

answers:

2

hi there

I've got a trait that looks like this (some further information can be found at this related question by myself although I don't think, it's needed for this question)

trait Extractor[-A,+B] {
  def extract(d:A):B
  //lots of other things
}

To use this in an existing java framework I would like this Extractor to either have a function that returns a Comparator[B] (being java.util.Comparator) or even better extend Comparator[A]. Now that poses a problem because Comparators type parameter is ought to be invariant, while A is contravariant and B is covariant.

So I get errors like this:

scala> import java.util.Comparator
import java.util.Comparator

scala> trait Extractor[-A,+B] extends Comparator[A]
<console>:6: error: contravariant type A occurs in invariant position in type [-A,+B]java.lang.Object with java.util.Comparator[A] of trait Extractor
       trait Extractor[-A,+B] extends Comparator[A]
             ^


scala> trait Extractor[-A, +B] {                 
     |   def comp:Comparator[B]
     | }
<console>:7: error: covariant type B occurs in invariant position in type => java.util.Comparator[B] of method comp
         def comp:Comparator[B]
             ^

Do you see any way out of this or is this just one of those cases where "using java generics in scala hurts"?

+12  A: 

With help of type-bounds it's possible to do the following:

scala> trait Extractor[-A, +B] {
     | def comp:Comparator[_ <: B]
     | }
defined trait Extractor
Vasil Remeniuk
thanks. That works. The code is not running yet but your code and the effective declaration of the Comparator compile save and sound. Thank you so much.
Agl
I know this is a whole different question but is there a good paper/tutorial/blog covering type-bounds and variants? I already read about it but one could argue that I didn't learn too much from them ;) (on the other hand, maybe that's just me. So all read them all again)
Agl
This one is pretty good (though it's not up-to-date -- doesn't have information about some 2.8 features) : http://programming-scala.labs.oreilly.com/ch12.html
Vasil Remeniuk
until i DO read more about this, just let me make sure, I understand what you are doing here. `[_ <: B]` says "what ever the type parameter may be, it has to be a subtype of `B`". Right? Shouldn't (in a perfect world) this information derive from the usage of `+B` in `Extractor[-A, +B]`?
Agl
Thanks for the reading material. Already planed to work my way through that book . . .
Agl
+4  A: 

You can make Extractor[A,B] extend Comparator[A] by using the @uncheckedVariance annotation.

scala> import scala.annotation.unchecked.uncheckedVariance
import scala.annotation.unchecked.uncheckedVariance

scala> trait Extractor[-A,+B] extends java.util.Comparator[A @uncheckedVariance]
defined trait Extractor

@uncheckedVariance is safe here because Comparator could have been defined as Comparator[-T]. There was a discussion around making Ordering covariant for Scala 2.8 using this annotation.

Edit See this question for more about @uncheckedVariance.

Ben Lings
uh that's a nice one too. Actually this could be the version that ends up in my code . . . as soon as I find the time to read that thread you posted. Thanks a lot!
Agl