オブジェクト指向超入門〜第8回〜

前回の記事では、例外という文法が導入された最大の目的は「エラーの発生を無視できない」よう強制させる事だと書きました。この事がオブジェクト指向とどう関係するのかについて解説します。

オブジェクト指向の重要なポリシーの1つに、保持しているデータが矛盾や破綻している状態のオブジェクトは一瞬たりとも存在してはいけない、というのがありました。(「オブジェクトは常に正しい」参照)従ってnewした直後にはすでに、各メンバ変数に正しい値が詰まっているオブジェクトが生成されている必要があり、その為にコンストラクタがあるという話でした。ではそのコンストラクタの実行中に何らかの致命的なエラーが発生して、正しい値をメンバ変数に代入してやる事が出来ない事態が発生したらどうしたらいいでしょうか。
例えば、外部の設定ファイルに書いてある値を読み込んでそれをメンバ変数の初期値にするという仕様で、その設定ファイルの読み込み時にIOエラーが起こって値を取得できなかったら...この例の場合はもちろんデフォルト値を代入するなどの手も考えられますが、そういった回避手段が無い事態が起こった場合、仕方なくエラーを返すしかないケースもあるでしょう。

ところで、オブジェクト指向言語の文法では「コンストラクタは戻り値を返さない」という事になっています。voidとも違って、そもそも型の記述さえしません。本当にコンストラクタは戻り値を返さないのでしょうか?戻り値を返せないので、コンストラクタでエラーが発生した場合、他の手段でそれを通知しないといけません。その為に例外が導入されたのでしょうか。そもそも何故そんな制限のある文法になっているのでしょう。

これらの疑問に対する答えは、オブジェクトを生成する以下のコードの記述の仕方を見れば自然と分かります。
 Hoge hoge = new Hoge();
そう!コンストラクタは戻り値を返すのです。その戻り値とは「自クラスのインスタンス」です。コンストラクタの定義に型の指定を書かないのは、戻り値が無いからなのではなく、戻り値の型は自分のクラスだと決まっているのでわざわざ書く必要が無いからです。

もしインスタンスとは別にエラーコードを(第2の?)戻り値として返せると仮定してみましょう。new のコードの記法がどうなるのかは置いといて、コンストラクタ内で致命的なエラーが発生しそれを戻り値で通知した場合、Hogeクラスの変数hogeには不完全な状態のインスタンスが代入されてしまいます。これは上記のオブジェクト指向のポリシーに反して、破綻した状態のオブジェクトが一瞬存在してしまう事になります。さらには返されたエラーコードを無視して後続の処理を続ければ、そのオブジェクトは一瞬どころか堂々とメモリ上に居座り続ける事も出来てしまいます。オブジェクト指向のポリシーから考えると、これはどうしても避けなければならない由々しき事態です。

つまり、コンストラクタでエラーが起こった場合、戻り値を返せないから仕方なく例外で通知するのではなく、戻り値があろうが無かろうが例外を投げなければならないのです。例外を投げた場合、上記 hoge = の代入は実行されることなく、直ちに例外ハンドラへ飛ばされます。変数hogeの指すメモリ上に不完全なインスタンスが一瞬でも生成される事はなくなる訳です。
これが「オブジェクト指向のポリシーを貫く上で例外は無くてはならない機能」だと前回の記事の冒頭で書いた理由です。