mixel mixel - 10 days ago 7
Scala Question

Could not find implicit value inside singleton object

I have this code:

trait Context {
implicit val e: Encoder

trait Encoder {
def write(): Unit = {
println("Test")
}
}

}

trait AsyncEncoders {
this: Context =>

class AsyncEncoder extends Encoder {
}

implicit val e = new AsyncEncoder()
}

class ConcreteContext extends Context with AsyncEncoders {
}


When I use it like this (case 1):

object Main extends App {
implicit val c = new ConcreteContext()

import c._

implicitly[Encoder].write()
}


then it compiles and prints
Test
.

But when I try to call the same code inside singleton object (case 2):

object TestObject {
def apply()(implicit c: ConcreteContext): Unit = {
import c._
implicitly[Encoder].write()
}
}

object Main extends App {
implicit val c = new ConcreteContext()

TestObject()
}


compilation fails with:


path/to/Main.scala:29: could not find implicit value for parameter e: c.Encoder
implicitly[c.Encoder].write()


If I change (case 3):

implicit val e = new AsyncEncoder()


to

implicit val e: Encoder = new AsyncEncoder()


then it compiles and runs as expected.

But for some reason this is not acceptable for me.

Why does compilation fail in the above case?

Answer

As it said in comments there is no issue in Scala 2.12.0.

For Scala 2.11.8 I used the following workaround assuming that Encoder will have only one method:

trait Context {
  implicit val e: Encoder

  type BaseEncoder = () => Unit

  type Encoder <: BaseEncoder
}

trait AsyncEncoders {
  this: Context =>

  type Encoder = BaseEncoder

  class AsyncEncoder extends BaseEncoder {
    override def apply(): Unit = {
      println("Test")
    }
  }

  implicit val e = new AsyncEncoder()
}

class ConcreteContext extends Context with AsyncEncoders {
}

object TestObject {
  def apply()(implicit c: ConcreteContext): Unit = {
    import c._
    implicitly[Encoder].apply()
  }
}

object Main extends App {
  implicit val c = new ConcreteContext()

  TestObject()
}