Timma
Timma

Reputation: 663

Implicit value not found in method to method call

I'm trying to add a helper method to a config library by using implicit classes and type classes. However, I am extremely new to Scala (1 week) and have been unable to find out why the following code issues a compile error (I provide the working solution in a comment in the code)

Simplification of the third party package:

package pkg

class Config {
  def hasPath(path: String) = { false }
  def getString(path: String) = { "str" }
  def getInt(path: String) = { 7 }
  def getDouble(path: String) = { 3.14d }
}

And my example file:

import pkg._

object Helpers {

  trait Extractor[T] {
    def extract(cfg: Config, path: String): T
  }

  object Extractor {

    implicit object IntExtractor extends Extractor[Int] {
      def extract(cfg: Config, path: String) = {
        99
      }
    }

  }

  implicit class BetterConfig(cfg: Config) {

    def extract[T](path: String)(implicit extractor: Extractor[T]): T = {
      extractor.extract(cfg, path)
    }

    // This example works if I add the implicit parameter:
    // (implicit extractor: Extractor[T])
    def extract[T](path: String, default: T): T = {
      if ( cfg.hasPath(path) ) {
        extract[T](path)
        //        ^ error here
      } else { 
        default
      }
    }
  }
}


object Demo extends App {

  import Helpers._

  val cfg = new Config
  val x = cfg.extract("foo", 3)

  println(s"x: ${x}")
}

This code gives the error could not find implicit value for parameter extractor: Helpers.Extractor[T]

Why can't the implicit value be found when calling extract(path) from within extract(path, default)? My understanding of the scoping rules or resolving the implicit, is wrong. I would have thought that when the call to extract(path) was made from within extract(path, default), the implicit would still be resolved from the companion object of Extractor.

I have tried this with Scala 2.10.6 and 2.11.8.

Upvotes: 1

Views: 252

Answers (1)

Alexey Romanov
Alexey Romanov

Reputation: 170745

Your call needs an implicit Extractor[T], where nothing is known about T. It would be resolved from the companion object, if there was one, but there is no such method there.

Imagine it worked. Then

val cfg = new Config
val x = cfg.extract[String]("foo", "")

should also compile. But how would it work without an implicit Extractor[String] anywhere?

Upvotes: 2

Related Questions