Reputation: 7278
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?
Upvotes: 11
Views: 2285
Reputation: 7278
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]
}
Upvotes: 4
Reputation: 139028
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.
Upvotes: 11