Using some time during the weekend, I decided to finally explore one the new features in the coming Scala 2.10, macros. Macros are also written in Scala so in essence a macro is a piece of Scala code, executed at compile-time, which manipulates and modifies the AST of a Scala program.
To do something useful, I wanted to implement a simple macro for debugging; I suppose I’m not alone in using println-debugging, that is debugging by inserting statements like:
running a test, and checking what the output is. Writing the variable name before the variable is tedious, so I wanted to write a macro which would do that for me; that is:
should have the same effect as the first snippet (it should generate code similar to the one above).
Let’s see step-by-step how to implement such a macro. There’s a good getting started guide on the scala macros page, which I used. All code explained below is available on GitHub, in the scala-macro-debug project.
1. PROJECT SETUP
To experiment comfortably we’ll need to setup a simple project first. We will need at least two subprojects: one for macros, and one for testing the macros. That is because the macros must be compiled separately and before and code that uses them (as they influence the compilation process).
Moreover, the macro subproject needs to have a dependency on scala-compiler, to be able to access the reflection and AST classes.
A simple SBT build file could look like this: Build.scala.
2. HELLO WORLD!
“Hello World!” is always a great starting point. So my first step was to write a macro, which would expand hello()
to println("Hello World!")
at compile-time.
In the macros subproject, we have to create a new object, which defines hello()
and the macro: