Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Scala 2.8 TreeMap and custom Ordering

I'm switching from scala 2.7 and ordered to scala 2.8 and using ordering. It looks quite straight forward but I was wondering could I make it a little less verbose. For example:

scala> case class A(i: Int)
defined class A
scala> object A extends Ordering[A] { def compare(o1: A, o2: A) = o1.i - o2.i}
defined module A

If I then try to create a TreeMap I get an error

scala> new collection.immutable.TreeMap[A, String]()
<console>:10: error: could not find implicit value for parameter ordering: Ordering[A]
       new collection.immutable.TreeMap[A, String]()
       ^

However if I explicitly specify the object A as the ordering it works fine.

scala> new collection.immutable.TreeMap[A, String]()(A)
res34: scala.collection.immutable.TreeMap[A,String] = Map()

Do I always have to explicitly specify the ordering or is there a shorter format?

Thanks

like image 447
David Avatar asked Apr 21 '10 14:04

David


3 Answers

Mind you, there's a slightly less verbose way of creating an Ordering:

implicit val OrderingA = Ordering.by((_: A).i)

The main advantage of Ordering being you can provide many of them for the same class. If your A class is truly Ordered, then you should just extend that. If not, instead of using implicits, you may pass an Ordering explicitly:

new collection.immutable.TreeMap[A, String]()(Ordering.by(_.i))
like image 130
Daniel C. Sobral Avatar answered Nov 04 '22 06:11

Daniel C. Sobral


Notice the word "implicit" in the diagnostic. The parameter is declared implicit meaning the compiler will try to find a suitable value in scope at the point you invoke the constructor. If you make your Ordering an implicit value, it will be eligible for this treatment by the compiler:

scala> implicit object A extends Ordering[A] { def compare(o1: A, o2: A) = o1.i - o2.i}
defined module A

scala> val tm1 = new collection.immutable.TreeMap[A, String]()
tm1: scala.collection.immutable.TreeMap[A,String] = Map()

Edit:

That example works in the REPL because the REPL encloses your code in invisible class definitions. Here's one that works free-standing:

case class A(val i:Int) extends Ordered[A] { def compare(o:A) = i - o.i }

object A { implicit object AOrdering extends Ordering[A] { def compare(o1: A, o2: A) = o1.i - o2.i } }

class B {
    import A.AOrdering

    val tm1 = new collection.immutable.TreeMap[A, String]()
}
like image 24
Randall Schulz Avatar answered Nov 04 '22 05:11

Randall Schulz


Instead of extending Ordering[A], try extending Ordered[A]. Like so:

scala> case class A(val i:Int) extends Ordered[A] {def compare(o:A) = i-o.i}
defined class A

scala> A(1)<A(2)
res0: Boolean = true

scala> A(1)<A(0)
res1: Boolean = false

scala> new collection.immutable.TreeMap[A, String]()
res3: scala.collection.immutable.TreeMap[A,String] = Map()
like image 45
Elazar Leibovich Avatar answered Nov 04 '22 05:11

Elazar Leibovich