MOCKSTACKS
EN
Questions And Answers

More Tutorials









Scala Macros

Examples

Macro Annotation


This simple macro annotation outputs the annotated item as-is.

import scala.annotation.{compileTimeOnly, StaticAnnotation}
import scala.reflect.macros.whitebox.Context
@compileTimeOnly("enable macro paradise to expand macro annotations")
class noop extends StaticAnnotation {
 def macroTransform(annottees: Any*): Any = macro linkMacro.impl
}
object linkMacro {
 def impl(c: Context)(annottees: c.Expr[Any]*): c.Expr[Any] = {
 import c.universe._
 c.Expr[Any](q"{..$annottees}")
 }
}

You can use the above-defined macro like this:

@noop
case class Foo(a: String, b: Int)
@noop
object Bar {
 def f(): String = "hello"
}
@noop
def g(): Int = 10

Method Macros


When a method is defined to be a macro, the compiler takes the code that is passed as its argument and turns it into an AST. It then invokes the macro implementation with that AST, and it returns a new AST that is then spliced back to its call site.

import reflect.macros.blackbox.Context
object Macros {
 // This macro simply sees if the argument is the result of an addition expression.
 // E.g. isAddition(1+1) and isAddition("a"+1).
 // but !isAddition(1+1-1), as the addition is underneath a subtraction, and also
 // !isAddition(x.+), and !isAddition(x.+(a,b)) as there must be exactly one argument.
 def isAddition(x: Any): Boolean = macro isAddition_impl
 // The signature of the macro implementation is the same as the macro definition,
 // but with a new Context parameter, and everything else is wrapped in an Expr.
 def isAddition_impl(c: Context)(expr: c.Expr[Any]): c.Expr[Boolean] = {
 import c.universe._ // The universe contains all the useful methods and types
 val plusName = TermName("+").encodedName // Take the name + and encode it as $plus
 expr.tree match { // Turn expr into an AST representing the code in isAddition(...)
 case Apply(Select(_, `plusName`), List(_)) => reify(true)
 // Pattern match the AST to see whether we have an addition
 // Above we match this AST
 // Apply (function application)
 // / \
 // Select List(_) (exactly one argument)
 // (selection ^ of entity, basically the . in x.y)
 // / \
 // _ \
 // `plusName` (method named +)
 case _ => reify(false)
 // reify is a macro you use when writing macros
 // It takes the code given as its argument and creates an Expr out of it
 }
 }
}

It is also possible to have macros that take Trees as arguments. Like how reify is used to create Exprs, the q (for quasiquote) string interpolator lets us create and deconstruct Trees. Note that we could have used q above (expr.tree is, surprise, a Tree itself) too, but didn't for demonstrative purposes.

// No Exprs, just Trees
def isAddition_impl(c: Context)(tree: c.Tree): c.Tree = {
 import c.universe._
 tree match {
 // q is a macro too, so it must be used with string literals.
 // It can destructure and create Trees.
 // Note how there was no need to encode + this time, as q is smart enough to do it itself.
 case q"${_} + ${_}" => q"true"
 case _ => q"false"
 }
}


Conclusion

In this page (written and validated by ) you learned about Scala Macros . What's Next? If you are interested in completing Scala tutorial, your next topic will be learning about: Scala Monads.



Incorrect info or code snippet? We take very seriously the accuracy of the information provided on our website. We also make sure to test all snippets and examples provided for each section. If you find any incorrect information, please send us an email about the issue: mockstacks@gmail.com.


Share On:


Mockstacks was launched to help beginners learn programming languages; the site is optimized with no Ads as, Ads might slow down the performance. We also don't track any personal information; we also don't collect any kind of data unless the user provided us a corrected information. Almost all examples have been tested. Tutorials, references, and examples are constantly reviewed to avoid errors, but we cannot warrant full correctness of all content. By using Mockstacks.com, you agree to have read and accepted our terms of use, cookies and privacy policy.