Search code examples
scalaimplicitplay-json

Why does the name of an implicit seem to affect its scope resolution in this example?


I am writing a simple JSON serializer for java.io.File just stingifying the path:

import java.io.File

import play.api.libs.json._
import Implicits.File._

object Implicits {
  object File {
    implicit val format: Format[File] = new Format[File] {
      override def writes(o: File): JsValue = JsString(o.toString)
      override def reads(js: JsValue): JsResult[File] = js.validate[String].map(f => new File(f))
    }
  }
}

final case class Bar(path: File) 

object Bar {
  implicit val format: Format[Bar] = Json.format
}

I find that the above does not work:

No instance of play.api.libs.json.Format is available for java.io.File in the implicit scope

However, if I change the name of Implicit.File.format to Implicit.File.fmt, it works fine.

Why does the name collide in this case when it should be the type, Format[File], that the implicit scope resolver should care about?

I'm using play-json 2.6.7.


Solution

  • Why does the name collide in this case when it should be the type, Format[File], that the implicit scope resolver should care about?

    Because it does care about the name as well.

    The actual arguments that are eligible to be passed to an implicit parameter of type T fall into two categories. First, eligible are all identifiers x that can be accessed at the point of the method call without a prefix and that denote an implicit definition or an implicit parameter. An eligible identifier may thus be a local name, or a member of an enclosing template, or it may be have been made accessible without a prefix through an import clause.

    At the line implicit val format: Format[Bar] = Json.format, format means Bar.format and not Implicits.File.format, so Implicits.File.format isn't eligible as an implicit by this rule. And it isn't in a companion object, so it isn't covered by the second category either.