James Kelleher
James Kelleher

Reputation: 2147

Is it possible to implicitly cast a generic type?

I'm working with a function that takes a list of email address records and returns the appropriate one for the use case. This list is passed to the function as an List[Map[String, String]], and the first step of the function is to cast each of the Map[String, String] members to a custom EmailAddress case class. Essentially, the relevant code looks like this:

val emails = List(Map("email_normalized" -> "[email protected]"))

object CaseClass {
  def identifyBestEmail(emails: List[Map[String, String]]): Map[String, String] = {
    val emailsCast = emails.map(emailFromMap)
    bestEmail(emailsCast)
  }

  def emailFromMap(x: Map[String, String]): EmailAddress = {
    EmailAddress(email_normalized = x.get("email_normalized").asInstanceOf[Option[String]])
  }

  def bestEmail(x: List[EmailAddress]) = {
    Map("email_normailzed" -> "the best")
  }

  case class EmailAddress(email_normalized: Option[String])
}

CaseClass.identifyBestEmail(emails)

I'm new to Scala and just learned about implicits, and I feel like there has to be a way to simply this to something like:

val emails = List(Map("email_normalized" -> "[email protected]"))

object ImplicitClass {
  def identifyBestEmail(emails: List[EmailAddress]): EmailAddress = {
    Map("email_normailzed" -> "the best")
  }

  implicit class EmailAddress(emailMap: Map[String, String])
}

ImplicitClass.identifyBestEmail(emails)

This latter example seems to me like it is much simpler, more flexible and easier to read than the previous one. However I can't figure out if there's a way to actually get it to work. When I try to run the code I get this error message:

error: type mismatch;
 found   : List[scala.collection.immutable.Map[String,String]]
 required: List[ImplicitClass.EmailAddress]

Am I on the right track here? Is there a cleaner way of handling the use case than what's in the first example?

UPDATE 1

This seems to work:

val emails = List(Map("email_normalized" -> "[email protected]"))

object ImplicitList {
  def identifyBestEmail(emails: EmailAddressList): Map[String, String] = {
    Map("email_normailzed" -> "the best")
  }

  implicit class EmailAddressList(emailList: List[Map[String, String]])
}

ImplicitList.identifyBestEmail(emails)

So I guess that means implicit conversions do not work on generic classes, you need to operate on the top level class.

Upvotes: 0

Views: 70

Answers (0)

Related Questions