stewSquared stewSquared - 16 days ago 9
Scala Question

Scala: How can an import prevent finding an implicit value?

I could use suggestions debugging an implicit:

I want to use the implicit,

x
:

type T
trait HasT {
implicit def x: T = ...
}


But I also need a wildcard import from some package
foo
. I've tried two different ways of introducing both:

class UseT extends HasT {
import foo._
implicitly[T] // fails! "could not find implicit value"
// use foo stuff
}

class Use T {
object hasT extends HasT
import hasT.x
import foo._
implicitly[T] // fails! "could not find implicit value"
}


Both fail with "could not find" (not "ambiguous implicits values").

This happens while implicit identifier
x: T
is accessible at the point of method call via either inheritance or importing.

My workaround is to rebind x to an implicit val before the import. Both of the following work:

implicit val x2: T = implicitly[T]
import foo._
implicitly[T] // works!


and

implicit val x2: T = x
import foo._
implicitly[T] // works!


What value could possibly be in foo to cause this behavior?

My first guess is that there is some competing implicit in
foo
, but if it were higher priority, the following
implicitly
would still work, and if it were an ambiguous implicit, I'd be getting a different a different error.

edit: Miles Sabin's guess was correct! I found the shadowing implicit: timeColumnType. I still don't completely understand given Som Snytt's observation that the shadowing implicit was wildcard imported while the shadowed was inherrited. But I'll leave the whole post here for posterity:

A second guess, offered by miles sabin, is implicit shadowing. I've since clarified my post to exclude that possibility. That case would be consistent with my errors if I had tried
package hasT extends HasT; import hasT._
, but As som-snytt points out, those two cases would not result in shadowing.

In my specific case, this can be confirmed by changing the name of the implicit I'm trying to use. (I must have missed a
publishLocal
or
reload
)

Now I'm actually trying to use slick. The implicit
T
above is actually a column type mapping:

import slick.driver.JdbcProfile

class Custom { ... } // stored as `Long` in postgres

trait ColumnTypes {
val profile: JdbcProfile
import profile.api._ // this is `foo` above
type T = profile.BaseColumnType[Custom]
implicit def customColumnType: T =
MappedColumnType.base[Custom, Long](_.toLong, Custom.fromLong)
}

class DatabaseSchema(val profile: JdbcProfile) extends ColumnTypes {
// `implicitly[T]` does not fail here.
import profile.api._ // this is also `foo` above
// `implicitly[T]` fails here, but it's needed for the following:
class CustomTable(tag: Tag) extends Table[Custom](tag, "CUSTOMS") {
// following fails unless I rebind customColumnType to a local implicit
def custom = column[Custom]("CUSTOM")
def * = custom
}
}


The type of
api
/
foo
is
JdbcProfile.API
. The offending implicit is probably here, but I can't tell why. I'll try blocking some of those from being imported and see if I can narrow it down.

Answer

I think it's most likely that foo contains a definition named x. When (wildcard) imported from foo it shadows the local definition,

scala> object foo { val x: Boolean = true }
defined object foo

scala> implicit val x: Int = 23
x: Int = 23

scala> implicitly[Int]
res0: Int = 23

scala> import foo._
import foo._

scala> implicitly[Int]
<console>:17: error: could not find implicit value for parameter e: Int
       implicitly[Int]
                 ^