Piotr Kowalczyk
Piotr Kowalczyk

Reputation: 11

Type argument is unchecked since it is eliminated due to erasure

I am getting this error while trying to filter "records" kept in a List. I am supposed to get a List[Map[String, String]] which will have all companies with their HQ locations.

non-variable type argument String in type pattern scala.collection.immutable.Map[String,String] (the underlying of Map[String,String]) is unchecked since it is eliminated by erasure
      case map: Map[String, String] if map.contains("company") => new Some(Company(map.get("company").get, map.get("origin").get))

I am just learning scala and I am not sure what to do, so that the type won't be lost during runtime

object Main {
  def main(args: Array[String]): Unit = {
    val data = List(
      Map("name" -> "Jan", "fname" -> "Kowalski", "age" -> "45"),
      Map("company" -> "ABB", "origin" -> "Sweden"),
      Map("name" -> "Katarzyna", "fname" -> "Nowak", "age" -> "45"), Map("company" -> "F4", "origin" -> "Poland"),
      List("Cos", "innego"),
      Map("company" -> "Salina Bochnia", "origin" -> "Poland"),
      Map("company" -> "AGH", "origin" -> "Poland"),
      Map("name" -> "Krzysztof", "fname" -> "Krol", "age" -> "14")
      )

      getCompanies(data)
  }
  
  def getCompanies(toFilter: List[Any]): List[Any] ={
    val result = for(record <- toFilter) yield filterRecords(record)
    result.toList.filter(_ != None)
  }

  def filterRecords(record: Any): Option[Company] ={
    record match{
      case map: Map[String, String] if map.contains("company") => new Some(Company(map.get("company").get, map.get("origin").get))
      case _ => None
    }
  }
}

case class Company (name: String, origin: String)

Upvotes: 1

Views: 1632

Answers (1)

AminMal
AminMal

Reputation: 3173

First, there are many resources about what type erasure is, why it happens and so on, so I wouldn't explain it here. Try better "typing", in your scenario, your data consists of either List[String] or Map[String, String], in Scala3 you can easily deal with it using Union Types, but a better solution would be to put restrictions on your input data and try wrapping them into something you would know about, in compile time. like this:

trait ListElement // can also be sealed, depends on what you have
case class ListHolder(value: List[String]) extends ListElement
case class MapHolder(value: Map[String, String]) extends ListElement

I would also create a companion object for the trait, for easier object creation:

object ListElement {
  def apply(arg: List[String]): ListElement = ListHolder(arg)
  def apply(arg: Map[String, String]): ListElement = MapHolder(arg)
}

Now let's re-create your data:

val data: List[ListElement] = List(
  ListElement(Map("name" -> "Jan", "fname" -> "Kowalski", "age" -> "45")),
  ListElement(List("Cos", "innego")),
  // ... other data here
)

Now I would rewrite your functions as follows, have better typing, are easier to track and safer:

def filterRecord(record: ListElement): Option[Company] = record match {
  case MapHolder(myMap) => myMap.get("company").map { companyName => 
    Company(
      companyName,
      myMap.get("origin").get // PLEASE do not use .get, .getOrElse would be safer
    )
   }
  case _ => None
}

def getCompanies(toFilter: List[ListElement]): List[Company] = 
  toFilter.map(filterRecord).collect {
    case Some(company) => company
  }

Upvotes: 1

Related Questions