Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Scala typeclasses implicit resolution

(Scala 2.11.8)

Consider the following code:

object ScalaTest extends App {
  class Wrapper {
    import Wrapper._

    def init(): Unit = {
      // "could not find implicit value for parameter tc: ScalaTest.Wrapper.TC[Int]"
      printWithTC(123)

      // Compiles
      printWithTC(123)(IntTC)

      // Compiles again!
      printWithTC(132)
    }
  }

  object Wrapper {
    trait TC[A] {
      def text(a: A): String
    }

    implicit object IntTC extends TC[Int] {
      override def text(a: Int) = s"int($a)"
    }

    def printWithTC[A](a: A)(implicit tc: TC[A]): Unit = {
      println(tc.text(a))
    }
  }

  (new Wrapper).init()
}

I have a bunch of questions regarding this piece of code:

  1. Why doesn't IntTC get resolved in the first place?
  2. Why it compiles after being used once? (if you comment out the first invocation, code works)
  3. Where should typeclass implicits be placed to get resolved properly?
like image 924
Alex Abdugafarov Avatar asked Oct 17 '22 11:10

Alex Abdugafarov


1 Answers

Use a val with a explicit return type. See https://github.com/scala/bug/issues/801 and https://github.com/scala/bug/issues/8697 (among others).
Implicit objects have the same issue as implicit vals and defs with inferred return types. As for your second question: when IntTC is used explicitly you force the compiler to typecheck it, so after that point its type is known and can be found by implicit search.

class Wrapper {
  import Wrapper._

  def init(): Unit = {
    // Compiles
    printWithTC(123)

    // Compiles
    printWithTC(123)(IntTC)

    // Compiles
    printWithTC(132)
  }
}

object Wrapper {
  trait TC[A] {
    def text(a: A): String
  }

  implicit val IntTC: TC[Int] = new TC[Int] {
    override def text(a: Int) = s"int($a)"
  }

  def printWithTC[A](a: A)(implicit tc: TC[A]): Unit = {
    println(tc.text(a))
  }
}

If you really want your implicit to be evaluated lazily like an object, you can use an implicit lazy val with an explicit type.

like image 98
Jasper-M Avatar answered Oct 21 '22 04:10

Jasper-M