I just noticed that Scala has macros, but I have never seen any code that uses them. They also seem quite different from C preprocessor macros and the like. Reading through the overview of macros, it didn't look like they offer anything that wasn't previously possible in Scala. Under the motivation heading, there is a list of things that macros enable:
- Language virtualization (overloading/overriding semantics of the original programming language to enable deep embedding of DSLs),
- Program reification (providing programs with means to inspect their own code),
- Self-optimization (self-application of domain-specific optimizations based on program reification),
- Algorithmic program construction (generation of code that is tedious to write with the abstractions supported by a programming language).
Later on in the menu, there are experimental macro features, such as type macros, quasiquotes, untyped macros and even more. Clearly there is a demand for this!
All these seem like nice features for people who build very sophisticated libraries with strong understanding of Scala. But do macros offer something for the average Scala developer too? Will using macros make my Scala code better?
As an "average" Scala developer, you will most likely not write macros yourself, unless you have very good reason.
Macros are a method of compile time meta programming, that is to say you program programs. For example, a def-macro—which is part of Scala 2.10 albeit still "experimental"—looks like a regular method, but whenever you call that method in your code, the compiler will replace that call with whatever that macro hidden behind that method will produce (a new code fragment).
A very simple example. Incorporate the date when your project was compiled into the code:
import java.util.Date
import reflect.macros.Context
import language.experimental.macros
object CompileTime {
def apply(): Date = macro applyImpl
def applyImpl(c: Context)(): c.Expr[Date] = {
import c.universe._
val now = System.currentTimeMillis() // this is executed during compilation!
val nowExpr = c.Expr[Long](Literal(Constant(now)))
val code = reify(new Date(nowExpr.splice))
c.Expr(code.tree)
}
}
Using that macro (the following code must be compiled separately from the macro code above):
object MacroTest extends App {
println(s"This project was compiled on ${CompileTime()}")
}
(If you run that multiple times, you see that the compile time is indeed constant)
So in short, macros offer a functionality which was not available in any previous Scala version. You can do things with macros you cannot do otherwise (often you can write similar things using runtime reflection, but macros are checked at compile time).
As a user you will however be exposed more and more to libraries which incorporate macros, because they can provide powerful constructs which are fully type safe. For example, automatic serialisers for JSON from a case class can be realised with macros, because the macro can inspect the type of your case class and build the correct program structure (AST) to read and write that case class, with no danger of runtime failure.
Some random links
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With