2014年5月7日水曜日

Scala 2.10

つい先日Scala 2.11がリリースされたばかりですが、タイトルの「Scala 2.10」は間違いではありません。

一昨年の後半からとあるシステム開発に注力していたため時間が取れずブログ更新を中断していましたが、ようやく一段落してきたので、自分向けに技術情報の棚卸しをしていくという意味でもぼちぼち書いていきたいと思います。

最近うれしかったことの一つはようやく製品開発にScala 2.10+Scalaz 7を使えるようになったことです。システムは一度動き始めると、なかなか使用しているコンパイラ、ライブラリ、ミドルウェアのバージョンを上げることはできません。特にバージョン間での互換性が高くないことで有名(?)なScalaの場合はなおさらですが、Akkaを本格的に使おうとするとさすがにそうもいっておられず、大量のコンパイルエラーと警告を克服してやっとScala 2.10+Scalaz 7に上げることができたしだいです。

ということで、(いまさらですが)Scala 2.10を本格的に使ってみた感想です。

  • warningの強化
  • Try
  • Future
  • Implicit Class/Value Class
  • feature機能
  • String Interpolation

warningの強化

Scala 2.10で、予想外にうれしかったことが「==」の型チェック機能の強化です。この機能のお陰で移植時に復数のバグを見つけることができました。

scala> val x = Some("5")
val x = Some("5")
x: Some[String] = Some(5)

scala> val y = "5"
val y = "5"
y: String = 5

scala> println(x == y)
println(x == y)
<console>:16: warning: comparing values of types Some[String] and String using `==' will always yield false
              println(x == y)
                        ^
false

ただ、改めて試してみると:

def f(a: String, oa: Option[String]): Boolean = a == oa

といったケースでは警告はでないようです。

また:

List(1, 2, 3).contains("5")

といったcontainsメソッドの型チェック問題は依然としてオープンです。

==メソッドやcontainsメソッドにおける型安全な等価性は、Scalaプログラミングで非常に重要なプログラミングテクニックだと思うので、いずれ取り上げてみたいと思います。

Try

Tryの導入によって2.10でプログラミングスタイルが大きく変わることは想定済みだったので、TryとNonFatalは2.9にバックポートして使っていました。このため、特に大きな問題はなく移行することができました。

想定外だったのが、ScalazでTryをMonadとして扱うことができない点です。例外が発生した時のTryの振舞いがモナド則を満たさないという問題があるようで、それが原因でScalaz側でTryの各種型クラスは提供していないのかなと思います。

ScalazでTryをサポートしていないため、Tryを使ってMonadicプログラミングすることに限界が出てきます。この辺りの事情も織り込んだ上で、例外をハンドリングする作戦を考えていく予定です。

Future

FutureはAkka Futureをほぼimport先を切り替えるだけで移植できました。

想定外だったのが、Tryと同様にScalazでMonadとして扱えない点です。Tryと同様に例外は発生した時の振舞いがモナド則を満たさないのが原因ではないかと推測します。

Scalazは、独自にFutureを用意しているので、MonadicプログラミングをするためにはこちらのFutureを使う事になりそうですが、本家Futureと併用することになるのでできれば避けたいところです。

Implicit Class/Value Class

Implicit Class/Value Classは、自分で直接使うことは今の所ほぼありません。ただ、型クラス機能を使用する際のオーバーヘッドが大幅に減少したはずなので、Scalazのような型クラスを多用するライブラリを安心して使えるようになりました。心理的な効果が非常に大きいです。

feature機能

implicit conversionはScalaの魅力的な機能の一つですが、バグが出た時のデバッグがとても大変になるので、ボクのコーディング戦略ではほぼ使わない機能になっています。具体的には、いわゆる「Pimp My Libraryパターン」で既存クラスを文脈依存で拡張したり、DSLの枠組み上必要な場合、以外は使わない機能です。

Scala 2.10からfeature機能が入って、拡張機能はコンパイルのパラメタかプログラム内で指定しないと警告が出るようになりました。上述のimplicit conversionもこの拡張機能に入っているので警告対象になりました。無自覚に使っている場合も警告によって存在を認識することができ重宝しました。

このimplicit conversion以外にも、今回のScala 2.10化では以下の警告が出ました。

  • postfixOps
  • existentials

postfixOpsはDSL的には残念ですが、非推奨の文法になったということなので、ソースコードを修正して対応しました。

プログラミング言語は互換性も大事ですが、Scalaのような伸び盛りの言語は新しい応用を取り込んでいくチャレンジも重要なので、feature機能とdeprecation機能によって時代遅れになってしまった機能、一般の開発者は使わない方がよい機能をうまく制御していくアプローチは非常によいと思いました。

String Interpolation

String Interpolationは:

  • s Interplatorやf Interpolatorの機能
  • String Interpolationの外部追加Iterpolatorへの期待
  • String InterpolationのInterpolator機能の開発

といった所が切り口になりますが、今の所はs Interplatorがそれなりに便利かな、という利用レベルです。

以前はformatメソッドを使っていましたが、引数の数を間違えると以下のようなランタイムエラーが出るのが問題点としてありました。この問題が起きなくなるのが、体感的に感じたs Interplator導入の直接のメリットでした。もちろん、s Interplatorの方が若干性能向上も期待できるのは重要です。

> "%s = %s".format("1 + 1")
java.util.MissingFormatArgumentException: Format specifier 's'
...

SlickのSQL Interpolationといった応用が沢山出てくると色々と面白くなってきそうです。

Scala 2.11

Scala 2.11については、とりあえずはPlayの対応待ちというところです。

Scala 2.11はTuple /Case classの22個制限が外れるのが大きな魅力ですが、それ以外は特別に使ってみたい機能はないようなので、実際に使いはじめるのはまた1年後ぐらいということになるかもしれません。

2 件のコメント:

  1. 7.1.0-M4から入ってます

    https://github.com/scalaz/scalaz/blob/v7.1.0-M6/core/src/main/scala/scalaz/std/Future.scala

    また、scalaz7.0.x系の場合は、別ライブラリですがこっち
    https://github.com/typelevel/scalaz-contrib/blob/v0.1.5/scala210/main/scala/Future.scala
    https://github.com/typelevel/scalaz-contrib/blob/v0.1.5/scala210/main/scala/Try.scala
    にFutureとTryのインスタンスあります

    返信削除
  2. 情報ありがとうございます!
    TryとFutureの型クラスがあればプログラミングが楽になりそうです。
    試してみたいと思います。

    返信削除