It's easy to write hygienic macros in Scala by using reify
and eval
. But it's not always possible to use reify
and eval
.
So, if one can't use them, what are the rules that will ensure that a macro is hygienic? And is there any way to test a macro to ensure that no bad hygiene has slipped through the cracks?
upd. In later milestones of 2.10.0, Expr.eval
got renamed to Expr.splice
.
Reify is hygienic, because it saves symbols along with Ident and This trees.
If your macro expansion result doesn't have symbols attached to idents (e.g. you have just Ident("x") to specify a reference to something named x), then subsequent typechecking of the macro expansion will bind x to whatever is in scope of the call site (or if that scope does not have an x, you will get a compilation error).
To the contrast, when your macro expansion has symbols for its idents, typechecker doesnt attempt to re-resolve them, and simply uses what it has. This means that when you reify an expression and use the result in a macro expansion, then it will carry its symbols into the call site. Well, not all symbols, e.g. it is impossible to refer to local variables or to private/protected things, but references to globally accessible declarations are persisted.
Bottom line is that to check whether your macro is hygienic, check whether your idents and thises have symbols attached to them. You can achieve this by reifying or by manually assigning symbols to your hand-crafted trees.
Since reify
is a macro, I'd just look at its implementation to figure out what it does.
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