I have got 'diverging implicit expansion' error and can't find what is wrong.
There are some dummy classes to isolate the problem:
import shapeless._
type Field = String
trait Column[T]
trait Parameter
trait Row
implicit object IntColumn extends Column[Int]
implicit object DoubleColumn extends Column[Double]
trait Mapper[T] {
def unmap(l: T): Seq[Parameter]
def map(row: Row): T
}
type MapperFactory[L] = (List[Field] => Mapper[L])
object Mapper {
def apply[L](fields: List[Field] = Nil)(implicit mapper: MapperFactory[L]) = mapper(fields)
}
There is the code I expect to work or at least to compile:
trait LowPriorityMapperImplicits {
implicit def fromMapper[H](implicit mapper: Mapper[H]): MapperFactory[H] = fields => mapper
}
object DivergingMapper extends LowPriorityMapperImplicits {
implicit def caseMapper[L, H <: HList](implicit generic: Generic.Aux[L, H], mapper: MapperFactory[H]): MapperFactory[L] = ???
implicit def hListMapper[H, T <: HList](implicit hMapper: MapperFactory[H], tMapper: MapperFactory[T]): MapperFactory[H :: T] = ???
implicit def hNilMapper: MapperFactory[HNil] = ???
implicit def singleMapper[H](implicit to: Column[H]): MapperFactory[H] = ???
}
And here are test cases:
trait F[X] {
import DivergingMapper._
//import LazyMapper._
implicit protected val xMapper: Mapper[X]
// t1-t5 work
val t0 = Mapper[A]()
val t1 = Mapper[X]()
val t2 = Mapper[A]()
val t3 = Mapper[X]()
val t4 = Mapper[(A, A)]()
val t5 = Mapper[(X, А)]()
// t6-t7 don't
// diverging implicit expansion for type com.ardtrade.db.XMapper.MapperFactory[...]
// starting with method caseMapper in object XMapper
val t6 = Mapper[(A, X)]()
val t7 = Mapper[(X, X)]()
}
I can't understand why Mapper[(X, A)]
works, but Mapper[(A, X)]
doesn't.
Update:
I tried to use shapeless.Lazy
and it compiles, but I've got NPE getting value from lazy implicit.
Trying to answer Miles Sabin's request to post the version with Lazy which results in NPEs, I found out that my test case actually compiles and works with Lazy version:
object LazyMapper extends LowPriorityMapperImplicits {
implicit def caseMapper[L, H <: HList](implicit generic: Generic.Aux[L, H], mapper: MapperFactory[H]): MapperFactory[L] = ???
implicit def hListMapper[H, T <: HList](implicit hMapper: MapperFactory[H], tMapper: Lazy[MapperFactory[T]]): MapperFactory[H :: T] = ???
implicit def hNilMapper: MapperFactory[HNil] = ???
implicit def singleMapper[H](implicit to: Column[H]): MapperFactory[H] = ???
}
I had NPEs due to the following implicit:
implicit def fromMapper[H](implicit mapper: Mapper[H]): MapperFactory[H] = fields => mapper
// every time we declare a new mapper as implicit val
// and there is no way to create it properly
// we get self initialization
// with null without any compile error
implicit val nullMapper = Mapper[ABRACADABRA]()
It's my fault, but it is still not clear for me why we need Lazy at all, so the question still stands.