piotr
piotr

Reputation: 5745

scala macro with fresh identifier

I have a macro which I want to use to log the time it takes to execute a block that might return something useful. So if I have something like val y = f(x) I will change to val y = Timed(f(x)) to get the time it took to execute the function in the log.

I almost have what I want, but when using fresh term names to avoid name collision, for example between t0 and t1, I'm getting an error:

Error:(22, 15) Can't unquote reflect.runtime.universe.TermName, consider providing an implicit instance of Liftable[reflect.runtime.universe.TermName]
         val $kk = System.nanoTime()
          ^

How to get those freshTermNames working with the quasiquotes?

import scala.language.experimental.macros
import scala.reflect.macros.blackbox.Context
import scala.reflect.runtime.{ universe ⇒ u }

object Timed {
  def apply[T](block: ⇒ T): T = macro Timed.apply_impl[T]

  def apply_impl[T: c.WeakTypeTag](c: Context)(block: c.Expr[T]): c.Expr[T] = {
    import c.universe._
    implicit val cc: c.type = c
    val kk = u.internal.reificationSupport.freshTermName("kk")
    val t0 = c.freshName("t0")
    val t1 = c.freshName("t1")
    val tdiff = c.freshName("tdiff")
    val blk = c.freshName("blk")
    val t0n = "t0"
    println(t0)
    val res = c.Expr(
      q"""
         val $kk = System.nanoTime()
         $block
         val t1 = System.nanoTime()
         val tdiff= t1 - t0
         log.debug("Took: {}", tdiff)
         $block
       """)
    println("Timing block: ")
    println(show(res))
    res
  }
}

Upvotes: 0

Views: 342

Answers (1)

Michael Zajac
Michael Zajac

Reputation: 55569

You don't want a TermName, you want an Ident:

val kk = Ident(TermName("kk"))

But if the name of the identifier is constant, there is no reason to even construct the identifier like that, when you could have just wrote:

q"""
   val kk = System.nanoTime
   ...
"""

Changing that will fix that problem, but there are others. t0 is undefined within the quasiquotes, and all of the other term names you've defined don't actually do anything.

I don't see why you need a macro for this, either, when a normal method does the job just fine. The macro will increase the size of your code (significantly if you use it a lot).

Upvotes: 0

Related Questions