2

I have a value of type Any. If its class is Map[String, Any] I must be able to cast it to a case class and for this purpose I'm using the solution proposed by Travis Brown here. The problem is that when I define a Typeable implementation as the following, in certain cases, I get the diverging implicit expansion error:

  implicit def caseClassTypeable[T, R <: HList](implicit castT: Typeable[T],
                                            gen: LabelledGeneric.Aux[T, R],
                                            fromMap: FromMap[R]) = 
new Typeable[T] {
  override def cast(t: Any): Option[T] = t.cast[Map[String, Any]] flatMap (m => to[T].from(m))

  override def describe: String = castT.describe
}

REPL session:

scala> import shapeless.syntax.typeable._
import shapeless.syntax.typeable._

scala> case class Simple(foo: String, bar: Int)
defined class Simple

scala> val m: Any = Map("foo" -> "a", "bar" -> 42)
m: Any = Map(foo -> a, bar -> 42)

scala> m.cast[Simple]
res7: Option[Simple] = Some(Simple(a,42))

scala> val l: Any = List(1, 2, 3)
l: Any = List(1, 2, 3)

scala> l.cast[List[Any]]
<console>:22: error: diverging implicit expansion for type shapeless.Typeable[List[Any]]
starting with method inrTypeable in object Typeable
       l.cast[List[Any]]
             ^

However this one works:

scala> l.cast[List[Int]]
res9: Option[List[Int]] = Some(List(1, 2, 3))

Any idea?

Community
  • 1
  • 1
lambdista
  • 1,850
  • 9
  • 16
  • This is a very confusing example. It looks to me as though what's failing here are the casts to `List[Any]` and `List[List[Any]]`, and I think these are most likely failing because your `caseClassTypeable` is being considered as applicable (becase `List[Any]` conforms to `T` and because it is directly accessible). I suspect that those casts will succeed if `caseClassTypeable` isn't in scope. In any case, it will help a lot if you simplify that example as much as possible (ie. remove the outmost `Map`). – Miles Sabin Oct 15 '15 at 13:26
  • Thank you for your comment @MilesSabin. I simplified the example by removing the outmost `Map`. I suspected the reason was the applicability of `caseClassTypeable` to `List[Any]`. Of course if I comment out `caseClassTypeable` the cast to `List[Any]` works but, unfortunately, I cannot cast a `Map[String, Any]` to a case class anymore. Any idea on how I can have my cake and eat it too? – lambdista Oct 15 '15 at 13:38
  • This simplest option would be to ensure that `caseClassTypeable` is only in scope where you need it. – Miles Sabin Oct 16 '15 at 10:54
  • @MilesSabin I had thought of this type of solution but how could I define a method `def asClass[T]...` where I include `caseClassTypeable` inside it and call it without having to specify the `R` type? I mean, I want to be able to write `m.asClass[Simple]` and not `m.asClass[Simple, ...]` where the definition of `asClass` would be `def asClass[T, R <: HList]`. Sorry if this is not very clear, I had a bad week. :) – lambdista Oct 16 '15 at 12:23

0 Answers0