marcin_koss
marcin_koss

Reputation: 5882

Issue with HashMap ordering on generic type in Scala

This is a simplified code to explain what happens. There are different type of Column classes one here is IntColumn. There are also ShortColumn, LongColumn etc. GetMin does some processing on values from file and needs to return min value. Value type depends on Column type.

abstract class Column[A] {
    val name: String
    val size: Int
    def stringToValue(s: String): A
}

case class IntColumn(name: String) extends Column[Int] {
    val size = 4
    def stringToValue(s: String): Int = s.toInt
}

val col = IntColumn("id")

import scala.collection.mutable.HashMap

def getMin[A](col: Column[A]): (A, Int) = {
    val hm = HashMap[A, Int]()

    // process some data from csv file...

    hm.put(col.stringToValue("1"), 1)
    hm.put(col.stringToValue("2"), 1)
    hm.put(col.stringToValue("3"), 1)

    hm.min // get min HashMap item
}

val min = getMin(col) // expecting (1, 1) of type (Int, Int)

When executing getMin I get the error below. I thought compiler here has enough information to figure out what A is and be able to compare values in a HashMap.

Error:(21, 9) No implicit Ordering defined for (A, Int).
    hm.min
       ^
Error:(21, 9) not enough arguments for method min: (implicit cmp: Ordering[(A, Int)])(A, Int).
Unspecified value parameter cmp.
    hm.min
       ^

Upvotes: 0

Views: 191

Answers (1)

Kolmar
Kolmar

Reputation: 14224

At the point of hm.min call the compiler only has knowledge that the key of the hash map is some abstract type A. It doesn't automatically keep track of any implicits associated with abstract types.

There are basically two ways to solve this:

  1. Either change the definition of getMin to take this implicit Ordering:

    def getMin[A: Ordering](col: Column[A]): (A, Int)
    

    At the point of getMin call the compiler knows that the argument has a concrete type Column[Int]. It will be able to figure out the implicit Ordering and pass it to getMin.

  2. Or make the Column hold the Ordering for its content type:

    abstract class Column[A](implicit val ord: Ordering[A])
    

    The Ordering will be provided and stored from column creation val col = IntColumn("id")

    You would also have to make this Ordering available for hm.min by importing it in getMin:

    def getMin[A](col: Column[A]): (A, Int) = {
      import col.ord
      // ... everything else stays the same
    

Upvotes: 3

Related Questions