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?
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.
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]
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With