Consider a Scala macro-based annotation such as @memoise from macmemo. The annotation requires two arguments: a max cache size and a time-to-live, e.g.,
@memoize(maxSize = 20000, expiresAfter = 2 hours)
Say you want to create a @cacheall
annotation that is equivalent to @memoize(maxSize = Int.MaxValue, expiresAfter = 100 days)
in order to reduce boilerplate and have a single point of parameterization.
Is there a standard pattern for this type of reuse? Obviously,
class cacheall extends memoize(Int.MaxValue, 100 days)
won't work because of the compile-time argument parsing in the macro.
Standard pattern is to make your annotation a macro annotation that being expanded switches on necessary annotation with necessary parameters.
import scala.annotation.StaticAnnotation
import scala.language.experimental.macros
import scala.reflect.macros.blackbox
class cacheall extends StaticAnnotation {
def macroTransform(annottees: Any*): Any = macro cacheallMacro.impl
}
object cacheallMacro {
def impl(c: blackbox.Context)(annottees: c.Tree*): c.Tree = {
import c.universe._
val memoize = q"""
new _root_.com.softwaremill.macmemo.memoize(
_root_.scala.Int.MaxValue, {
import _root_.scala.concurrent.duration._
100.days
})"""
annottees match {
case q"${mods: Modifiers} def $tname[..$tparams](...$paramss): $tpt = $expr" :: _ =>
q"${mods.mapAnnotations(memoize :: _)} def $tname[..$tparams](...$paramss): $tpt = $expr"
}
}
}