Scalaマクロ Tips: マクロを使った静的チェックの事例紹介 2013年10月18日

今回はマクロを使った静的(コンパイル時)チェックの事例についていくつか紹介したいと思います。

前の記事でScalaのマクロを使う用途の一つとして静的チェックの強化を挙げました。 Scalaは静的型付き言語なのでコンパイル時に型のチェックがおこなわれますが、どうしてもチェックできないところもあります。 たとえば文字列の中身は型ではチェックできないので実行時エラーにするということになります。 そういったところをマクロを使ってコンパイル時に調べるという例を見ていきます。

文字列

一番最初に思いつくのは前述したように文字列です。String Interpolationとの組み合わせも考えられます。

まず紹介するのはScalaの標準ライブラリに入っているString Interpolationのfです。 これはよくあるprintf系のフォーマット文字列のString Interpolation版ですが、マクロによって型チェックされるようになっています。 フォーマットと引数の型が合っていないものはコンパイルエラーになります。 詳しくは公式のドキュメントがあるのでそちらを見てください。

文字列の補間 - Scala Documentation

同じように正規表現についてもマクロでのチェックが考えられます。 検索するといくつか出てくると思いますが、吉田さんが記事を書かれているので紹介します。

Scalaでコンパイル時に正規表現をチェックする「マクロかつString Interpolation」 - scalaとか・・・

単にコンパイル時に実行して例外を上げるだけで、結構便利なものになりますね。

同じく吉田さんがマクロでJSONの文字列をjson4sのオブジェクトにするというライブラリを書かれています。 これも文字列に問題があった場合はコンパイル時のエラーになります。

コンパイル時に、 String を lift json に変換する macro - scalaとか・・・

マクロによってSQLに型をつけようというライブラリもあります。

jonifreeman/sqltyped

文字列の静的チェックというのはマクロの有力な使い道の一つでしょう。

Type Dynamic

ScalaにはType Dynamic、もしくは、Dynamicトレイトと呼ばれる仕組みがあります。 これはメソッド呼び出しをメソッド名の文字列に変換することによって、 動的型付け言語でよくあるように、あらかじめ定義していないメソッドでも自由に呼べるようにするという機能です。 特にDSLで使うと便利な機能だと思います。

このDynamicとマクロを組み合わせることによって自由にメソッドを呼べるようにしつつ静的チェックもおこなえるようになります。 このことについてはseratchさんが記事を書かれているので紹介します。ScalikeJDBCでも使われているようです。

Type Dynamic を type safe に扱う方法 - seratch

他にはアクセッサオブジェクトやデリゲートオブジェクトを作るのに使われていることが多いようです。 関数型プログラミングで使われるLensというアクセッサオブジェクトの生成ライブラリがいくつかあるのですが、その元祖と言ってもいいMacrocosmを紹介します。

retronym/macrocosm

MacrocosmはScalaのマクロ誕生初期に生まれたライブラリなのですが、defマクロでできることがわかりやすい形で一通り書かれているのではないかと思います。 僕は一年くらい前にこのライブラリを読んでマクロを勉強しました。

あ、他のLensの実装も吉田さんがまとめられていますね。

ScalaでのLens実装まとめ - scalaとか・・・

このDynamicとマクロの組み合わせは "Poor man's type macros" とも呼ばれているらしいです。 一応マクロで型らしきものを作ることができるということでしょうね。 他にも色々と応用が考えられそうです。

その他

その他の例をいくつか見ますと、AkkaにTyped Channelsというものがあります。

Typed Channels (EXPERIMENTAL) — Akka Documentation

Actorがやりとりするメッセージは通常コンパイル時にはチェックされません。 これをマクロを使って静的にチェックしようというものです。

これも吉田さんがブログで触れられてますね。さすがですね。

northeast scala symposium 2013 の video を見た感想 - scalaとか・・・

あとAltJSのRoyの作者でScala界隈でも関数型系の怖い人の一人として知られているBrian McKennaさんが作られたWartRemoverというlintツールがマクロでも使えるようです。

Scala Code Linting via WartRemover 0.4 - BAM Weblog

puffnfresh/wartremover

Lint系ツールは元のコードに手を加えたくないという都合上、コンパイラ・プラグインとして提供されることが多いと思いますが(たとえば HairyFotr/linter など)、 構文木のチェックの手法はマクロでも応用できるものだと思います。

今回はマクロを使った静的チェックの事例を紹介しました。 defマクロの性質上、コード生成がやりづらく、型が強いということで、この分野はよく発達してきたと思います。 型がなくコード生成がしやすいマクロアノテーションの登場で、これからどう発展していくのかというのも気になるところです。