Can I make an impassioned plea to the powers that be to make scala.math.{Ordering, PartialOrdering, Equiv} contravariant in their type parameter? I know, having tried it, that the necessary code changes to the traits themselves are straightforward, if not trivial. However, after reading
http://www.scala-lang.org/node/3786, I get the impression that there is some obscure technical obstruction having something to do with contravariant type-inference and F-bounded polymorphism. (I would be most interested if someone could explain it to me in more detail). How serious is this problem? Are there any easy workarounds? Is there a ticket open for this?
That was the plea. Now for some passion: Of course, all these traits are naturally contravariant and having them invariant is nearly as bad as having List[T] be invariant. It is an embarrassing blight on an otherwise beautiful library (I was about to say language). I'm finding more and more of my code riddled with silly boilerplate like
implicit val ordering2: Ordering[Bar] = implicitly[Ordering[Foo]].on(identity)
when I need an ordering on Bar <: Foo and I have an implicit ordering on Foo (in the more annoying cases, Bar is something like SomeLongAnnoyingPrefix#SomeAbstractTypeThatIsReallyAFoo). And, of course, I have to do this for every different Bar that extends Foo. But at least asking for an implicit Ordering[Bar] and only supplying an Ordering[Foo] results in a compile time error. I ran into a more insidious bug last week when I was (unknowingly) asking for an implicit Equiv[Bar] when I had defined an implicit Equiv[Foo]. The code looked something like
def assertEq[T](x: T, y: T)(implicit e: Equiv[T]) = ...
implicit cmp: Equiv[Foo] = ...
assertEq(q.x, p.x)
As far as I was concerned, the type of the expressions q.x and p.x was Foo, and I had defined an implicit Equiv[Foo]. But the compiler figured out that T was some strange compiler generated type that happened to be a Foo, but had slightly more context, and therefore my implicit didn't apply--BUT, the compiler happily supplied my assertEq with the universal (equality based) Equiv[SomeStrangeCompilerType#ThatHappensToBeAFoo], and so my program compiled just fine. It took me a good number of hours to figure out why is wasn't doing what I intended.
In the end my solution was to define my own contravariant Equiv[-T]. I fear I may go the route of defining my own Ordering and PartialOrdering as well if the standard library can't be fixed. Please don't make me do it!