2010年3月3日水曜日

Optionとnull

2月28日にOptionについて取り上げた。

Optionを使用する本質的な意味は、オブジェクト間の関連における多重度を仕様として明確に記述すること。さらに、仕様違反を文法違反として検出することである。

多重度は0以上の整数値の集合として記述することができるけど、一般的には以下の4種類を基本とすればよい。

  • 1:必ず存在する。
  • 0または1:存在する場合と存在しない場合がある。
  • 1以上:1以上複数個存在する。存在しない場合はない。
  • 0以上:存在しないか複数存在する。

XML的には、それぞれ「記号なし」(必ず存在する)、「?」(0または1)、「+」(1以上)、「*」(0以上)の記号で表現したくなるところだ。

Javaのnullの問題とは、突き詰めていくと「必ず存在する(多重度1)」という仕様を記述することが不可能だったということである。

たとえば、Javaで以下のようなコードがあった場合、インスタンス変数zip, prefecture, cityやメソッドgetAddressの型を見ただけでは「必ずStringオブジェクトが格納されている/返ってくる(多重度1)」のか「nullが格納/返ってくることがある(多重度0または1)」のかということは分からない。安全サイドに立つと「nullが格納/返ってくることがある(多重度0または1)」を前提にプログラミングすることになるけど、これはプログラミングを著しく煩雑にする。多くの場合、インスタンス変数やメソッドを提供する側の意図は「必ずStringオブジェクトが格納されている/返ってくる(多重度1)」なので、利用者側で安全策を取らざるを得ないのは無駄な作業とも言える。

Person.java
public class Persion {
  String zip;
  String prefecture;
  String city;

  public String getAddress() {
    return (zip + " " + prefecture + " " + city)
  }
}

実用的な意味でのnullの問題はこの多重度の齟齬によってバグの温床になることである。

たとえば、上記のPerson.javaのgetAddressメソッドにはバグがある。

インスタンス変数zip, prefecture, cityのいずれかがnullの場合、出力される文字列に「null」という文字が含まれなんとも情けないことになるだろう。if文を使ってこの問題を回避するコードは当然書けるけど、大した処理もしていないのに悲しいほど煩雑なコードになる。

2月28日に取り上げたPerson.scala(以下に再掲)では、この多重度の問題をOptionを使ってきちんと記述できている。これに違反した場合にはコンパイラが文法エラーとして教えてくれる。

Person.scala
class Person(val name: String) {
  var zip: Option[String] = None
  var prefecture: Option[String] = None
  var city: Option[String] = None

  def address: String = {
    (for (Some(s) <- List(zip, prefecture, city)) yield s).mkString(" ")
  }
}

ScalaはJavaとの連携の問題もあってnullをサポートしている。このため、Person.scalaを以下のようにnullを使って実装することもできるけれど、ScalaにはOptionがあるのでわざわざnullを使うこともないだろう、ということである。

PersonNull.scala
class Person(val name: String) {
  var zip: String = null
  var prefecture: String = null
  var city: String = null

  def address: String = {
(for (s <- List(zip, prefecture, city); if s != null) yield s).mkString(" \
    ")
  }
}

とはいえ、ここで大事なのは、Optionを使うとプログラミングの手間が増えないのかということである。いくら理論的に美しい文法であってもプログラミングで大きな手間がかかるようであると、実用上は使えない。

ここで登場するのがScalaが関数型言語であるということ。関数型言語の特徴を活かしたコーディングをするとOptionを使うことで逆にプログラミングが楽になるのである。仕様を美しく正確に記述できて、仕様違反を文法エラーとして検出してくれる上に、プログラミングまで楽になるのであれば使わない手はないだろう。

もちろん、Optionを使って楽をするためには色々なイディオムを知っておく必要がある。追々ブログで取り上げていこうと思う。

0 件のコメント:

コメントを投稿