Search code examples
scalafunctional-programmingscala-2.10implicitsscala-implicits

implicit function that compares two closed classes in Scala


I am working with a Location object from another closed API and it already has a toString() method that returns a String. I just want an implicit function that can compare two Location instances by comparing their toString() values. So I will be able to go

val L1 = new Location(**Parameters for Location**)
val L2 = new Location(**Parameters for Location**) 
if (L2 > L1) { **do something** } 

Solution

  • Consider providing an implicit conversion to an instance of type Ordered:

    case class Location(x: Int, y: Int, s: String)
    
    import scala.math.Ordered
    
    implicit class LocationOrdered(val loc: Location) 
    extends Ordered[LocationOrdered] {
      def compare(other: LocationOrdered): Int = {
        this.loc.toString.compare(other.loc.toString)
      }
    }
    
    val a = Location(123, 456, "foo")
    val b = Location(456, 789, "bar")
    
    println("a = " + a + " b = " + b)
    
    if (a > b) println("a > b") else println("! a > b")
    if (a >= b) println("a >= b") else println("! a >= b")
    if (a <= b) println("a <= b") else println("! a <= b")
    if (a < b) println("a < b") else println("! a < b")
    

    In this way, you automatically get all the other comparison methods <=, <, >=, > for free.


    As @AlexeyRomanov has pointed out, it is usually preferable to have an implicit Ordering in scope, because for example List.sort requires it as an implicit argument. The implementation would be even shorter than for Ordered:

    import scala.math.Ordering
    import scala.math.Ordering._
    
    implicit object LocationOrdering extends Ordering[Location] {
      def compare(a: Location, b: Location) = a.toString.compare(b.toString)
    }
    

    This would allow us to compare the Location values like this:

    val locationOrdering = implicitly[Ordering[Location]]
    import locationOrdering._
    val a = Location(123, 456, "foo")
    val b = Location(456, 789, "bar")
    
    if (a > b) println("a > b") else println("! a > b")