Macros

マクロバンドル

Language

EXPERIMENTAL

Eugene Burmako 著
Eugene Yokota 訳

マクロバンドル (macro bundle) は、Scala 2.11.x および Scala 2.12.x 系列に含まれる機能だ。マクロバンドルは Scala 2.10.x では実装されていない。Scala 2.10.x 向けのマクロパラダイスでも、これは実装されていない。

マクロバンドル

Scala 2.10.x においてマクロ実装は関数として表されている。コンパイラがマクロ定義の適用を見つけると、マクロ実装を呼び出すという単純なものだ。しかし、実際に使ってみると以下の理由によりただの関数では不十分なことがあることが分かった:

  1. 関数に制限されることで複雑なマクロのモジュール化がしづらくなる。マクロのロジックがマクロ実装外のヘルパートレイトに集中していて、マクロ実装がヘルパーをインスタンス化するだけのラッパーになってしまっているのは典型的な例だ。
  2. さらに、マクロのパラメータがマクロのコンテキストにパス依存であるため、ヘルパーと実装をつなぐのに特殊なおまじないを必要とする。

マクロバンドルは、マクロ実装を c: scala.reflect.macros.blackbox.Contextc: scala.reflect.macros.whitebox.Contextをコンストラクタのパラメータとして受け取るクラス内で実装することで、コンテキストをマクロ実装側のシグネチャで宣言しなくても済むようになり、モジュール化を簡単にする。

import scala.reflect.macros.blackbox.Context

class Impl(val c: Context) {
  def mono = c.literalUnit
  def poly[T: c.WeakTypeTag] = c.literal(c.weakTypeOf[T].toString)
}

object Macros {
  def mono = macro Impl.mono
  def poly[T] = macro Impl.poly[T]
}

blackbox vs whitebox

マクロバンドルは、blackboxwhitebox の両方のマクロの実装に使うことができる。マクロバンドルのコンストラクタのパラメータに scala.reflect.macros.blackbox.Context の型を渡せば blackbox マクロになって、 scala.reflect.macros.whitebox.Context ならば whitebox マクロになる。