Timma Timma - 2 months ago 14
Scala Question

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.

Answer

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?

Comments