I'll start with an example. Here's an equivalent of List.fill for tuples as a macro in Scala 2.10:
import scala.language.experimental.macros
import scala.reflect.macros.Context
object TupleExample {
def fill[A](arity: Int)(a: A): Product = macro fill_impl[A]
def fill_impl[A](c: Context)(arity: c.Expr[Int])(a: c.Expr[A]) = {
import c.universe._
arity.tree match {
case Literal(Constant(n: Int)) if n < 23 => c.Expr(
Apply(
Select(Ident("Tuple" + n.toString), "apply"),
List.fill(n)(a.tree)
)
)
case _ => c.abort(
c.enclosingPosition,
"Desired arity must be a compile-time constant less than 23!"
)
}
}
}
We can use this method as follows:
scala> TupleExample.fill(3)("hello")
res0: (String, String, String) = (hello,hello,hello)
This guy is a weird bird in a couple of respects. First, the arity argument must be a literal integer, since we need to use it at compile time. In previous versions of Scala there was no way (as far as I know) for a method even to tell whether one of its arguments was a compile-time literal or not.
Second, the Product return type is a lie—the static return type will include the specific arity and element type determined by the arguments, as shown above.
So how would I document this thing? I'm not expecting Scaladoc support at this point, but I'd like to have a sense of conventions or best practices (beyond just making sure the compile-time error messages are clear) that would make running into a macro method—with its potentially bizarre demands—less surprising for users of a Scala 2.10 library.
The most mature demonstrations of the new macro system (e.g., ScalaMock, scala macros documentation scala-2.10 scala-macros