こんにちは。このクラスでは Pharo の強力な例外をお見せします。
概要をお見せします。
例外で何ができるのでしょう？ 例外から復帰(resume)できます。
再実行(restart)もできます。 新しい例外としてシグナルします。
例外を最初に使うための 実用上役にたつものだけを
お見せしましょう。
しかし、これが全てだというのでは ありません。
例外には 2 種類あります。 致命的なものが多いエラーと
通知です。 通知は要らないということができ
参考のためにあります。
もし、例外についての
完璧なリファレンスが必要であれば
この書籍 Deep Into Pharo の 章が 1 つまるまるあります。
この Mooc のウェブサイト上で 無料で提供されています。
では何を学ぶのかというと 例外を挙げて捕捉することと
普段から使うことができる 便利なヘルパーメソッドです。
基本的には
この講義でやることは全て このページに書いてあります。
例外を捕捉するための ハンドラをインストールします。
例外をシグナルして
2 つの便利なメッセージをやります。 ensure: と ifCurtailed: です。
では見てみましょう。
例外を捕捉したいとしましょう。
on:do: メッセージを使います。
ブロックを用意しておいて何かしていて
例外が起きたらどうなるでしょう。
ここで something をします。 例外が引数として渡されます。
ゼロ除算の例を見てみます。
7 を 0 で割ると
ゼロ除算で何が起こるかというと
ゼロ除算があるぞ！と言います。
ここで注目することは この例外クラスのインスタンスが
引数として渡されて
例外に質問したりメッセージを送ることが できるということです。
なぜなら、Pharo では例外は オブジェクトだからです。
例外の中でメッセージを送って
何かをして、0 となります。
では、どうやって例外を起こすのでしょう？
基本的に、例外を生成して それに signal メッセージを送ります。
ここでは、警告を与えたい場合には Warning new
例外を生成して、カスタマイズして メッセージを設定します。
そして signal メッセージを送ります。
著者名を尋ねる例外 AuthorNameRequest クラスがあり
メソッドを書けば
他の API として使えます。
AuthorNameRequest がこの API を 定義するからです。
そこで 文字列 'Stef' を渡して signal します。
通常は
クラスが signal するショートカットを 提供して、生成せずに済むようにします。
OutOfMemory はクラスです。 このクラスに signal メッセージを送ります。
通常は警告文をつけて Warning new なんとかかんとか、とはしません。
Warning signal: として文字列をつけます。 そのほうが短く書けます。
ただし例外によります。
ユニットテストをするアジャイルな プログラミングや
テスト駆動なプログラミングで
例外が起こったことをどうやって テストしたら良いでしょう？
shouldnt:raise や should:raise: を使います。
一緒に読んでみましょう。
ここで
2 月の日付を生成する時に
SubscriptOutOfBounds 例外は
挙がって欲しくない、と書きます。
では、13 月の日付を生成する時には
エラーが発生しなければならない とします。
まあ普通はそんな日付はないですね。
そこで should:raise: を使います。
つまり
13 月の日付を作るとエラーになる ということです。
こうすることで例外についての
ユニットテストを書くことができます。
細かなことではありますが
これら 2 つのヘルパーメソッドを 知ることは重要です。
Pharo での例外には
Error があります。
メッセージを理解できない 添字エラー、ゼロ除算など。
Halt があります。 デバッグする時に見ることになります。
ブレークポイントを置いて
システムの実行を止めることができます。
Notification があります。 致命的でないものです。
例えば 廃止（Deprecation）です。 このメソッドは使うな。他のを使えと。
警告やタイムアウトもです。
おもしろいのは
UnhandledError です。
これがデバッガーを起動します。
通常は UnhandledError は使いませんが UnhandledError も Error の一種だと
いうことは知っておいてください。
例外は本物のオブジェクトです。
doesNotUnderstand: メッセージが
ProtoObject でどう定義されているか Pharo ブラウザで見ることができます。
そこでは MessageNotUnderstood new
message: と receiver: を送って signal します。
この例外は Point new strangeAndBizarre で起こります。
strangeAndBizarre メッセージは 知らないので。
そこで例外を作ります。
Deprecationは 例えば
まだ成長している API を使っていて
もう有効ではないと Pharo が決めた場合です。
実際…
Pharo では deprecated:on:in: を使います。
分かりやすい例を選んでみました。
menuItem title: は何を言っているかというと
title: のかわりに addTitle: を使えということです。
どう実装されているかというと
deprecated:... は
Deprecation という
例外を生成して
その例外オブジェクトに メソッドや説明を与えて
signal します。
deprecation も messageNotUnderstood も 例外で、例外を生成して挙げているということです。
これは細かいことになりますが 例外の集合 ExceptionSet もあります。
ZeroDivide や Warning が起こったら という記述ができます。
あるいはコンマで区切ることで
例外の集合を生成することができます。
これを使って これらの例外に反応する、と書けます。
滅多に使われません。 一通り見せるために説明しています。
では、より頻繁に使われる
便利なメソッドを見てみましょう。
ある表現式について プログラムがその手前で失敗しても。
その表現式が必ず実行されるとどうやって 確証を得ることができるでしょうか？
ensure: を使います。 ensure: は
何かをやっていて
別のブロックが実行されることを 保証します。
とても強力です。 例えば自動的にファイルをクローズできます。
Pharo のプロファイラーの spyOn: を見てみましょう。
プロファイリングを開始して
プロファイリング対象の このブロックを実行します。
そしてプロファイルを停止することを 保証します。
たとえプロファイル対象として渡された ブロックがエラーを起こしても。
もう1つ、とても便利なヘルパーがあります。
ある表現式が
プログラムが失敗した時だけ 実行されることを保証します。
何か変なことが起こったら
これを実行する、というものです。
wait の例は低レベルのもので
プロセッサーのスケジューリングを 変えるものです。
システムがセマフォをスケジュールして
何か不具合があったら
システムがスケジューラから
外すことを保証します。
これらのメソッドは とても手軽でパワフルです。
メソッド探索がどう動くかを説明する
スライドを
お見せしましたが
ここでは...
Pharo での例外では
別の結果を返したり 再実行したりできます。
プログラムの実行を変更して
例外が起こらなかったかのように 動くようにすることが
resume を使ってできます。
この例外はこのレベルでは扱いたくないから
より上位で扱ってほしい、ということが
例外を pass することで可能です。
古い例外を新しい例外で置き換えることも
resignal でできます。
これが必要な時には あなたは何をやっているか分かっているでしょう。
この章を読んで こういうことができるこということを
知っておいてください。
例外から別の返り値を返す時は return: を使います。
これを見てわかるように この値を返すブロックを渡して
例外を挙げると、最終的には
ブロックが返したこの値が返ってきます。 これが return: です。
では、resume: は何かというと
resume: では
ここで起こされた例外について
resume: すると
このハンドラで与えた値ではなく 次の値になります。
例外が発生した箇所から継続するのです。 なので、ここから再開します。
そしてこの値が得られます。
ではまとめます。
Pharo の例外は強力です。 ええ、いいですね。
とてもシンプルな API があります。 例外を挙げる signal と
例外を捕捉する on:do: と
この表現式が必ず実行されるように 保証する ensure: と
問題が発生するか否かで
発生した時に実行する ifCurtailed:
doSomething の中で問題が発生したら onProblem を実行します。
例外を使い始めるために必要なことは これで全てです。