Macro access to members of object where macro is defined

Posted by Marc Grue on Stack Overflow See other posts from Stack Overflow or by Marc Grue
Published on 2013-06-22T18:30:26Z Indexed on 2013/06/25 4:21 UTC
Read the original article Hit count: 516

Filed under:
|

Say I have a trait Foo that I instantiate with an initial value

val foo = new Foo(6) // class Foo(i: Int)

and I later call a second method that in turn calls myMacro

foo.secondMethod(7) // def secondMethod(j: Int) = macro myMacro 

then, how can myMacro find out what my initial value of i (6) is?

I didn't succeed with normal compilation reflection using c.prefix, c.eval(...) etc but instead found a 2-project solution:

Project B:

object CompilationB {
    def resultB(x: Int, y: Int) = macro resultB_impl
    def resultB_impl(c: Context)(x: c.Expr[Int], y: c.Expr[Int]) =
      c.universe.reify(x.splice * y.splice)
}

Project A (depends on project B):

trait Foo {
  val i: Int

  // Pass through `i` to compilation B:
  def apply(y: Int) = CompilationB.resultB(i, y)
}

object CompilationA {
  def makeFoo(x: Int): Foo = macro makeFoo_impl
  def makeFoo_impl(c: Context)(x: c.Expr[Int]): c.Expr[Foo] =
    c.universe.reify(new Foo {val i = x.splice})
}

We can create a Foo and set the i value either with normal instantiation or with a macro like makeFoo. The second approach allows us to customize a Foo at compile time in the first compilation and then in the second compilation further customize its response to input (i in this case)! In some way we get "meta-meta" capabilities (or "pataphysic"-capabilities ;-)

Normally we would need to have foo in scope to introspect i (with for instance c.eval(...)). But by saving the i value inside the Foo object we can access it anytime and we could instantiate Foo anywhere:

object Test extends App {
  import CompilationA._

  // Normal instantiation
  val foo1 = new Foo {val i = 7}
  val r1   = foo1(6)

  // Macro instantiation
  val foo2 = makeFoo(7)
  val r2   = foo2(6)

  // "Curried" invocation
  val r3 = makeFoo(6)(7)

  println(s"Result 1 2 3: $r1 $r2 $r3")
  assert((r1, r2, r3) ==(42, 42, 42))
}

My question

Can I find i inside my example macros without this double compilation hackery?

© Stack Overflow or respective owner

Related posts about scala

Related posts about scala-macros