読者です 読者をやめる 読者になる 読者になる

Effective Scalaの翻訳を少しだけ手伝わせてもらいました & 読んでて気になったところ。

scala translation

Effective Scalaが公開されて数日経ちました。
f:id:yosuke_furukawa:20120304205718p:image
Scalaはハイブリッド言語と言われるだけあって、命令型、関数型のスタイル両方共で書けるという素晴らしさを持っています。

Scalaにはバイブルともいうべき本がいくつか出ています。その中の一つが↓。

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

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

コレを読むとScalaで実施するためのmustな記法は知ることができます。ただ、こうするべき(should)というようなノウハウめいた記法は分かりません。

Effective Scalaを読むとTwitterのコアを書いている方々のノウハウが詰まっています。
翻訳にも少しだけ手伝わせてもらいました。
関数型プログラミングのところは少しだけお手伝いさせてもらっています。

さてさて、Effective Scalaを読んで、以下の所に気を惹かれました。

Javaとの互換性

我々は、Scala コードをJavaで利用するとき、Javaでの使い方を慣用的に残して良いものか確かめるようにしている。大体は余計な努力は必要ない。クラス群と実装を含まないトレイトはJava に正確に等価に対応される。しかし、時々、別にJava APIを提供する必要がある。あなたのライブラリのJava API の感じをつかむ良い方法は単体テストJavaで書くことである(ただコンパイルが通れば良い)。この点については Scala コンパイラーは不安定であるのだが、このテストによって、あなたのライブラリの Java 視点は安定さを維持できる。

TwitterではScalaからJavaを呼ぶ(Scala -> Java)だけじゃなく、JavaからScalaのモジュールも呼べるようにしている(Java -> Scala)
んだなぁと思いました。Twitterはコアの部分の殆どをScalaで書いていると聞いていますが、Javaとの相互互換性を保っておけばJavaで書かれたレガシーコードとも
連携できる、というのを狙っているんだと推察されます。

コレクションの以下の文面からもそれが見て取れます。

Javaコレクションとの相互運用のために、scala.collection.JavaConvertersを使おう。JavaConvertersは、暗黙変換を行うasJavaメソッドとasScalaメソッドを追加する。読み手を助けるために、これらの変換は明示的に行うようにしよう:

import scala.collection.JavaConverters._

val list: java.util.List[Int] = Seq(1,2,3,4).asJava
val buffer: scala.collection.mutable.Buffer[Int] = list.asScala

■末尾最適化の話
末尾最適化は素晴らしいが、ちょっとがっかりしたという話はこのブログで紹介しました。Effective Scalaを読んで、@tailrecアノテーションという方法で末尾最適化が適切に行われるのか検証できるという機能があったことを知りました。

再帰表現を使うと、問題をしばしば簡潔に記述できる。そしてコンパイラは、末尾呼び出しの最適化が適用できるコードを、正規のループに置き換える(末尾最適化が適用されるかは@tailrecアノテーションで確認できる)。

@tailrec
final def fixDown(heap: Array[T], i: Int, j: Int) {
  if (j < i*2) return

  val m = if (j == i*2 || heap(2*i) < heap(2*i+1)) 2*i else 2*i + 1
  if (heap(m) < heap(i)) {
    swap(heap, i, m)
    fixDown(heap, m, j)
  }
}

アノテーションで確認できるのは嬉しいですね。

■性能

高水準コレクションライブラリは、(高水準な構築物が一般的にそうであるように)性能の推測が難しい。コンピュータに直接指示するやり方、つまり命令型スタイルから遠ざかるほど、あるコード片が性能に与える影響を厳密に予測するのは困難になる。一方で、正確さを判断することは概して容易だし、読みやすさも向上する。Scalaの場合、Javaランタイムが事態をさらに複雑にしている。Scalaでは、ボクシング操作やアンボクシング操作がユーザから隠されており、性能やメモリ使用量の面で重大なペナルティを被ることがある。

Effective Javaにはボクシング/アンボクシング変換は基本的に使わないようにしたほうが良いと書かれています。
ボクシング/アンボクシング変換はコンパイルエラーになるようにしている所もあります。
性能面でのオーバーヘッドが大きいからです。

Scalaはそこがユーザから隠されています。なので、気をつけようがないということです。
この辺りはしょうがないのかもしれません。勿論世のコンパイラがそうであるように最適化処理が今後行なわれるようになっていけば
問題のない範囲に収まる可能性はあります。

ここで書かれているのは、プログラミングの作法にあるように性能にいきなりセンシティブになるべきではないと書かれています。
出来てから性能測定し、チューニングを入れよ、というのが根本的な思想です。

計測した後で、もしも性能にセンシティブなコードであればなるべく低水準なものを使うべきだと書かれています。
リストよりも配列、順列(シーケンス)よりもバッファを使うべきだとされています。
ただいきなり配列やバッファでゴリゴリ書いてはScalaの魅力も半減です。

面白い内容が多いです。Scalarの方々だけじゃなく、Javarの方々も是非読む事をオススメします。

GitHub Pages · File Not Found · GitHub