tl;dr

海外記事を読みます

Scala の機能がコンパイル速度に与える影響

compiletime というプロジェクトで、テストライブラリの選択や Scala の機能がコンパイル速度にどのように影響を与えるか計測した話。著者は ScalaTest の作者なので何かしらバイアスがかかっているのかもしれないが、(specs2 が遅いという)結果には体感的に納得感がある。

  • JUnitTestNG、ScalaTest、specs2 が対象。
  • コンパイルが速い順番に JUnitTestNG、ScalaTest で、specs2 はとても遅い。
  • コンパイル時間は以下に影響を受ける:
    • スコープ中の implicit の数
    • by-name パラメータの数
    • テストクラスのメソッドが trait によって提供されるか、親クラスから継承されるか
  • implicit に関しては、スコープに import された implicit の数とスコープ中の implicit の使用の数の積に依ると思われる。Scala コンパイラコンパイルエラーを発見したとき、スコープ内の implicit を見ていくが、都合のよい implicit を発見しただけでは終わらず、残りの implicit もぜんぶ舐めて他に合う implicit がないことを確かめる必要があるからだろう。
  • by-name〔ってのは specs2 でいうと "..." should "..." in につづくブロックのようなアレのことだろう〕だけでなく関数リテラルにも影響を受けそうだとあるが、きちんとした検証はしていないとのこと。
  • Scala 2.10 から scala.reflect.runtime.universe を用いてスコープ内の implicit をカウントできる。
  • グラフは上から順に、
    • テスト数を変化させながら、ScalaTest で assert(_ === _) を使用した場合、import ShouldMatchers._ した場合、with ShouldMatchers した場合のコンパイル時間。
    • 同上。
    • フレームワークで最速の方法を使った場合の、テスト数に対するコンパイル時間。ScalaTest は Spec、specs2 は mutable.Specification を使っている。
    • specs2 の記法に近いスタイルを採用したときの、テスト数に対するコンパイル時間。specs2.Specification が途中でガクッと落ちているのは OOM になるかららしい……。
    • 同上、縦軸は生成されるクラスファイル数。
    • 同上、縦軸は生成されるクラスファイルの総サイズ。

この結果をもとに、ScalaTest をこのように改良する方針だ、という話も書かれている。その他詳しい数字は原文を参照されたし。

Scalaスケーラブルプログラミング第2版

Scalaスケーラブルプログラミング第2版