Why can't Scala find my typeclass instance defined implicitly in the companion object, when the typeclass is not in a dedicated source file?
Asked Answered
E

1

1

Please refer to the source code below. All source code is defined in the same package. When I define all of the code within a single source file ShowMain.scala, I get a compile error, however when object ShowMain is defined in ShowMain.scala and trait Show and object Show are defined in Show.scala, there is no compile error.

My question: What is the cause for this? What language rule have I run afoul of?

Example code:

object ShowMain {

  def main(args: Array[String]): Unit = {
    output("hello")
  }

  def output[A](a: A)(implicit show: Show[A]) =
    println(show.show(a))

}

trait Show[-A] {
  def show(a: A): String
}

object Show {

  implicit object StringShow extends Show[String] {
    def show(s: String) = s"[String: $s]"
  }

}

Compile error:

(ScalaIDE/Scala 2.11.2 on line containing output("hello"))

Multiple markers at this line
    - not enough arguments for method output: (implicit show: test.typeclasses.show1.Show[String])Unit. Unspecified value 
     parameter show.
    - not enough arguments for method output: (implicit show: test.typeclasses.show1.Show[String])Unit. Unspecified value 
     parameter show.
    - could not find implicit value for parameter show: test.typeclasses.show1.Show[String]
    - could not find implicit value for parameter show: test.typeclasses.show1.Show[String]
Effie answered 24/8, 2014 at 4:37 Comment(0)
K
9

There's a rule that implicit has to be defined earlier in the compilation unit.

So, move object Show to the top and it compiles.

Alternatively,

object Show {
  //implicit object StringShow extends Show[String] {
  implicit val x: Show[String] = new Show[String] {
    def show(s: String) = s"[String: $s]"
  }
}

see the explanation about the type:

https://mcmap.net/q/655785/-why-does-this-explicit-call-of-a-scala-method-allow-it-to-be-implicitly-resolved

Krilov answered 24/8, 2014 at 5:8 Comment(2)
Thanks for the follow-up comment about the type ascription, I noticed that was the only way I could get the val to work, and was going to create a second question for that case.Effie
Understanding the type ascription requirement answered a lot of other questions I had about the compiler being able to find my implicits. Thanks!Effie

© 2022 - 2024 — McMap. All rights reserved.