|
| 1 | +--- |
| 2 | +layout: overview-large |
| 3 | +title: Macro Bundles |
| 4 | + |
| 5 | +disqus: true |
| 6 | + |
| 7 | +partof: macros |
| 8 | +num: 6 |
| 9 | +outof: 6 |
| 10 | +--- |
| 11 | +<span class="label important" style="float: right;">MACRO PARADISE</span> |
| 12 | + |
| 13 | +**Eugene Burmako** |
| 14 | + |
| 15 | +Macro bundles and macro compilers are pre-release features included in so-called macro paradise, an experimental branch in the official Scala repository. Follow the instructions at the ["Macro Paradise"](/overviews/macros/paradise.html) page to download and use our nightly builds. |
| 16 | + |
| 17 | +## Macro bundles |
| 18 | + |
| 19 | +Currently, in Scala 2.10.0, macro implementations are represented with functions. Once the compiler sees an application of a macro definition, |
| 20 | +it calls the macro implementation - as simple as that. However practice shows that just functions are often not enough due to the |
| 21 | +following reasons: |
| 22 | + |
| 23 | +1. Being limited to functions makes modularizing complex macros awkward. It's quite typical to see macro logic concentrate in helper |
| 24 | +traits outside macro implementations, turning implementations into trivial wrappers, which just instantiate and call helpers. |
| 25 | + |
| 26 | +2. Moreover, since macro parameters are path-dependent on the macro context, [special incantations](/overviews/macros/overview.html#writing_bigger_macros) are required to wire implementations and helpers together. |
| 27 | + |
| 28 | +3. As macros evolved it [became apparent](https://twitter.com/milessabin/status/281379835773857792) that there should exist different |
| 29 | +interfaces of communication between the compiler and macros. At the moment compiler can only expand macros, but what if it wanted to |
| 30 | +ask a macro to help it with type inference? |
| 31 | + |
| 32 | +Macro bundles provide a solution to these problems by allowing macro implementations to be declared in traits, which extend |
| 33 | +`scala.reflect.macros.Macro`. This base trait predefines the `c: Context` variable, relieving macro implementations from having |
| 34 | +to declare it in their signatures, which simplifies modularization. |
| 35 | + |
| 36 | + trait Macro { |
| 37 | + val c: Context |
| 38 | + } |
| 39 | + |
| 40 | +Referencing macro implementations defined in bundles works in the same way as with impls defined in objects. You specify a bundle name |
| 41 | +and then select a method from it, providing type arguments if necessary. |
| 42 | + |
| 43 | + import scala.reflect.macros.Context |
| 44 | + import scala.reflect.macros.Macro |
| 45 | + |
| 46 | + trait Impl extends Macro { |
| 47 | + def mono = c.literalUnit |
| 48 | + def poly[T: c.WeakTypeTag] = c.literal(c.weakTypeOf[T].toString) |
| 49 | + } |
| 50 | + |
| 51 | + object Macros { |
| 52 | + def mono = macro Impl.mono |
| 53 | + def poly[T] = macro Impl.poly[T] |
| 54 | + } |
| 55 | + |
| 56 | +## Macro compilers |
| 57 | + |
| 58 | +When I was implementing macro bundles, it became apparent that the mechanism which links macro definitions with macro implementations |
| 59 | +is too rigid. This mechanism simply used hardcoded logic in `scala/tools/nsc/typechecker/Macros.scala`, which takes the right-hand side |
| 60 | +of a macro def, typechecks it as a reference to a static method and then uses that method as a corresponding macro implementation. |
| 61 | + |
| 62 | +Now compilation of macro defs is extensible. Inste
8000
ad of using a hardcoded implementation to look up macro impls, |
| 63 | +the macro engine performs an implicit search of a `MacroCompiler` in scope and then invokes its `resolveMacroImpl` method, |
| 64 | +passing it the `DefDef` of a macro def and expecting a reference to a static method in return. Of course, `resolveMacroImpl` |
| 65 | +should itself be a macro, namely [an untyped one](/overviews/macros/untypedmacros.md), for this to work. |
| 66 | + |
| 67 | + trait MacroCompiler { |
| 68 | + def resolveMacroImpl(macroDef: _): _ = macro ??? |
| 69 | + } |
| 70 | + |
| 71 | +Default instance of the type class, `Predef.DefaultMacroCompiler`, implements formerly hardcoded typechecking logic. |
| 72 | +Alternative implementations could, for instance, provide lightweight syntax for macro defs, generating macro impls |
| 73 | +on-the-fly using `c.introduceTopLevel`. |
0 commit comments