Search code examples
scalaimplicit

Type mismatch on implicit type class conversion


I have the following piece of code

  trait HTMLWritable {
    def toHTML: String
  }

  case class User(name: String, age: Int, email: String) extends HTMLWritable {
    override def toHTML: String = s"<div> $name ($age) <a href=$email/> </div>"
  }

  trait HTMLSerializer[T] {
    def serialize(value: T): String
  }

  implicit object UserSerializer extends HTMLSerializer[User] {
    override def serialize(user: User): String = s"<div> ${user.name} (${user.age}) <a href=${user.email}/> </div>"

  }

  implicit class HTMLEnrichment[T](value: T) {
    def toHTML(serializer: HTMLSerializer[T]): String = serializer.serialize(value)
  }

  val john = User("John", 32, "[email protected]")

  println(john.toHTML(UserSerializer))

which produces the following error

Error:(30, 23) type mismatch;
 found   : advanced.StackOverflowQuestion.UserSerializer.type
 required: Int
  println(john.toHTML(UserSerializer))

the error will disappear if I rename HTMLWritable's toHTML method to toHtml or in general to something else and keeping the print statement intanct like so

 trait HTMLWritable {
    def tohtml: String
  }

  case class User(name: String, age: Int, email: String) extends HTMLWritable {
    override def tohtml: String = s"<div> $name ($age) <a href=$email/> </div>"
  }

and the question: Why is the compiler confused here?

I would expect that the class method would be preferred and only defer to the implicit if the method was not found but this type mismatch is a completely different beast.


Solution

  • Compiler thinks that .toHTML in john.toHTML(UserSerializer) is method HTMLWritable#toHTML instead of extension method HTMLEnrichment#toHTML.

    Then according to HTMLWritable#toHTML signature, john.toHTML is a String and john.toHTML(UserSerializer) is john.toHTML.apply(UserSerializer) i.e. String#apply expecting Int.