Caching implicit resolution
Asked Answered
S

2

11

To reduce compile times of my project, I'm caching certain type classes that are resolved by implicit lookups. This appears somewhat cumbersome though, because the straight forward implementation does not work:

scala> implicit val x: String = implicitly[String]
x: String = null

The implicit lookup considers its own, uninitialized definition as a valid implementation. A lazy val would blow the stack with infinite recursion. Therefore I'm currently handling it in this fashion:

implicit val x: String = cache.x

object cache {
   val x: String = implicitly[String]
}

But this makes it overly complicated, and the cache-definitions can not make use of other cached type classes easily (since they are not implicit).

Also, hiding the value itself from scope does unfortunately not work.

scala> :pas
// Entering paste mode (ctrl-D to finish)

object scope {
    implicit val x: String = {
        import scope.{ x => _ }
        implicitly[String]
    }
}

// Exiting paste mode, now interpreting.

defined object scope

scala> scope.x
res0: String = null

Is there a more elegant way to achieve an implicit resolution cache?

Statutable answered 21/12, 2015 at 15:38 Comment(2)
@Statutable Have you looked at Shapeless's cachedImplicit macro? It's very similar to what you're doing.Ararat
@TravisBrown that is exactly what I've been looking (and secretly hoping) for. I didn't come across it with my Google queries. If you move your comment into an answer I'll be happy to accept.Statutable
A
11

Shapeless provides a cachedImplicit macro with an implementation that's very similar to yours (it uses shadowing to avoid the recursion, and the fact that it's a macro means the usage can be cleaner).

There are some limitations to be aware of, and you may not want to take on a new dependency for this single method, but the implementation is pretty concise, and it's at least a good starting point.

Ararat answered 21/12, 2015 at 17:49 Comment(0)
S
4

Just for the sake of completeness: the shapeless macro in the accepted answer shadows its own definition in a way I didn't come up with. My particular problem could therefore be solved this way:

implicit val x: String = {
    def x = ???
    implicitly[String]
}
Statutable answered 22/12, 2015 at 15:40 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.