Scalaxy/MacroExtensions: a DSL / compiler plugin to write macro-based DSLs (enrichments without runtime dependency!)

Quick link: Scalaxy/MacroExtensions on GitHub

Scala’s enrich-my-library pattern allows Scala developers to add methods (and more) to existing classes.

Scala 2.10 facilitates this pattern by providing implicit classes:

This works great, but…

  • It usually implies some object creation at runtime (lightweight though it might be, expecially if the extension is a value class),
  • Your extension library is a new runtime dependency (which is not such a bad thing, but it can be avoided, please read on).

The other day, Eric Christiansen rightly complained on NativeLibs4Java’s mailing list that Scalaxy/Compilets were quite constrained by the typer, and that he wished he could define extension methods more easily.

I gave that a serious thought, and came up with a compiler plugin that runs before the typer / namer and performs the following expansion:

Quite exciting syntax twisting, but overall not a huge line-saver.

Then I realized there’s another pattern that could benefit from such rewrites: macros enrichments.

A macro enrichment?

A macro enrichment just extends the “enrich-my-library” pattern by implementing the extension method using a macro. As a result, the enrichment is “inlined” at compilation time, and there’s no runtime dependency nor overhead. See my recent experiments for examples of such macro enrichments:

Scalaxy/MacroExtensions just uses the exact same syntax as above to create all the implicit class / macro wiring necessary to implement the extension as a macro:

Update(Feb 22th 2013): Updated the syntax to use @scalaxy.extend instead of @extend.

The plugin supports two kinds of body for extension methods: regular code, and macro.

  • If the body looks like some regular method implementation, as above, it will wrap it in a reify call and will wrap all references to self and to the method parameters in splice calls.
  • If the body is a macro implementation, it will put it verbatim in the resulting macro:

If you find this cool, just give it a try! (and follow me on Twitter if you want to hear about my next experiments :-)).