1

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.

Yevgeny Terov
  • 36
  • 1
  • 5
  • Could you post the version with `Lazy` the results in NPEs? – Miles Sabin Apr 25 '16 at 07:30
  • @MilesSabin I was wrong and updated the question. The version with lazy works perfectly, although I don't quite understand why we need it. – Yevgeny Terov Apr 25 '16 at 17:50
  • Your example is a bit elaborate to unravel, but it will be recursion appearing somewhere in the implicit resolution which `Lazy` is controlling. See my other answer [here](http://stackoverflow.com/a/27911353/146737). – Miles Sabin Apr 26 '16 at 08:12

0 Answers0