Newbie Scala macros question about Expr type

Sorry for newbie question. I am learning scala macros. When trying the following code in scala REPL. it prints something like Expr[Nothing](3). Although the value a can be retrieved by v.tree, why is it type of Nothing instead of Int? Isn’t it wrapper of syntax tree of the parameter a? Thanks

def method1(a: Int): Int = macro impl

def impl(c: Context)(a: c.Expr[Int]): c.Expr[Int] = { 
  a match { 
    case v: c.Expr[Int] => println("v is captured => "+v)
    case rest@_ => println("rest: "+rest) 
  } 
  a 
}
1 Like

I don’t know why the compiler doesn’t assign the appropriate WeakTypeTag to the Expr. But if I were you I would just use Tree. A match like case v: c.Expr[Int] is fruitless anyway because of erasure.

def method1[T](a: T): T = macro impl

def impl(c: Context)(a: c.Tree): c.Tree = { 
  import c.universe._
  a match { 
    case v if a.tpe <:< typeOf[Int] => println("v is captured => " + v.tpe)
    case rest => println("rest: " + rest.tpe) 
  } 
  a 
}

This creates another question. When should I use Tree or when should I use Expr?

From scala api doc, it states that Expr wraps an abstract syntax tree and tags it with its type. Does that mean it does not matter, but when one wants more functions in manipulating the tree, then Expr is a better choice?

In addition, how can I separate value and type obtained by tpe ? What returned by tpe is Int(3), but I don’t find tree method in Context api doc[1], so not sure which api method should I use in order to retrieve the value I am looking for.

Thanks

[1]. http://www.scala-lang.org/api/2.11.7/scala-reflect/index.html#scala.reflect.macros.whitebox.Context

The only thing Expr gives you, as far as I know, is that you can use it together with reify.

scala> import scala.reflect.runtime.universe._ // more or less the same for macros
import scala.reflect.runtime.universe._

scala> reify(4)
res16: reflect.runtime.universe.Expr[Int] = Expr[Int(4)](4)

scala> reify{ val i: Int = res16.splice }
res17: reflect.runtime.universe.Expr[Unit] =
Expr[Unit]({
  val i: Int = 4;
  ()
})

But I thought quasiquotes are recommended over reify…

That seems to be a bit clearer for me, as it all provide a way to work with AST, like reify - “which provides a shortcut for creating ASTs”.

http://docs.scala-lang.org/overviews/macros/overview.html

Still many things I need learn, but it’s good to learn new lessons. Thank you very much for your explanation!