1 00:00:00,520 --> 00:00:03,800 こんにちは。このクラスでは Pharo の強力な例外をお見せします。 2 00:00:03,960 --> 00:00:06,400 概要をお見せします。 3 00:00:06,600 --> 00:00:09,160 例外で何ができるのでしょう? 例外から復帰(resume)できます。 4 00:00:09,520 --> 00:00:11,840 再実行(restart)もできます。 新しい例外としてシグナルします。 5 00:00:12,000 --> 00:00:16,240 例外を最初に使うための 実用上役にたつものだけを 6 00:00:16,400 --> 00:00:17,840 お見せしましょう。 7 00:00:18,000 --> 00:00:20,840 しかし、これが全てだというのでは ありません。 8 00:00:21,000 --> 00:00:24,600 例外には 2 種類あります。 致命的なものが多いエラーと 9 00:00:24,760 --> 00:00:27,680 通知です。 通知は要らないということができ 10 00:00:27,840 --> 00:00:29,160 参考のためにあります。 11 00:00:30,320 --> 00:00:32,800 もし、例外についての 12 00:00:32,960 --> 00:00:35,800 完璧なリファレンスが必要であれば 13 00:00:35,960 --> 00:00:39,640 この書籍 Deep Into Pharo の 章が 1 つまるまるあります。 14 00:00:39,800 --> 00:00:45,040 この Mooc のウェブサイト上で 無料で提供されています。 15 00:00:45,600 --> 00:00:50,640 では何を学ぶのかというと 例外を挙げて捕捉することと 16 00:00:50,800 --> 00:00:54,400 普段から使うことができる 便利なヘルパーメソッドです。 17 00:00:54,960 --> 00:00:55,800 基本的には 18 00:00:56,000 --> 00:00:58,440 この講義でやることは全て このページに書いてあります。 19 00:00:58,800 --> 00:01:02,360 例外を捕捉するための ハンドラをインストールします。 20 00:01:02,520 --> 00:01:03,480 例外をシグナルして 21 00:01:03,640 --> 00:01:08,280 2 つの便利なメッセージをやります。 ensure: と ifCurtailed: です。 22 00:01:09,400 --> 00:01:11,280 では見てみましょう。 23 00:01:11,840 --> 00:01:14,680 例外を捕捉したいとしましょう。 24 00:01:14,840 --> 00:01:16,880 on:do: メッセージを使います。 25 00:01:17,040 --> 00:01:20,120 ブロックを用意しておいて何かしていて 26 00:01:20,280 --> 00:01:23,160 例外が起きたらどうなるでしょう。 27 00:01:23,320 --> 00:01:27,280 ここで something をします。 例外が引数として渡されます。 28 00:01:27,920 --> 00:01:31,520 ゼロ除算の例を見てみます。 29 00:01:31,680 --> 00:01:34,960 7 を 0 で割ると 30 00:01:35,600 --> 00:01:38,120 ゼロ除算で何が起こるかというと 31 00:01:38,280 --> 00:01:41,640 ゼロ除算があるぞ!と言います。 32 00:01:41,800 --> 00:01:47,160 ここで注目することは この例外クラスのインスタンスが 33 00:01:48,360 --> 00:01:49,840 引数として渡されて 34 00:01:50,000 --> 00:01:52,600 例外に質問したりメッセージを送ることが できるということです。 35 00:01:52,760 --> 00:01:54,680 なぜなら、Pharo では例外は オブジェクトだからです。 36 00:01:54,840 --> 00:01:56,600 例外の中でメッセージを送って 37 00:01:56,760 --> 00:02:00,400 何かをして、0 となります。 38 00:02:00,800 --> 00:02:02,920 では、どうやって例外を起こすのでしょう? 39 00:02:03,240 --> 00:02:07,400 基本的に、例外を生成して それに signal メッセージを送ります。 40 00:02:07,560 --> 00:02:10,840 ここでは、警告を与えたい場合には Warning new 41 00:02:11,000 --> 00:02:15,240 例外を生成して、カスタマイズして メッセージを設定します。 42 00:02:15,400 --> 00:02:16,760 そして signal メッセージを送ります。 43 00:02:16,920 --> 00:02:21,000 著者名を尋ねる例外 AuthorNameRequest クラスがあり 44 00:02:21,160 --> 00:02:23,000 メソッドを書けば 45 00:02:23,160 --> 00:02:24,720 他の API として使えます。 46 00:02:24,880 --> 00:02:28,240 AuthorNameRequest がこの API を 定義するからです。 47 00:02:28,400 --> 00:02:30,440 そこで 文字列 'Stef' を渡して signal します。 48 00:02:30,600 --> 00:02:33,080 通常は 49 00:02:33,240 --> 00:02:38,040 クラスが signal するショートカットを 提供して、生成せずに済むようにします。 50 00:02:38,200 --> 00:02:41,640 OutOfMemory はクラスです。 このクラスに signal メッセージを送ります。 51 00:02:41,800 --> 00:02:44,800 通常は警告文をつけて Warning new なんとかかんとか、とはしません。 52 00:02:44,960 --> 00:02:48,840 Warning signal: として文字列をつけます。 そのほうが短く書けます。 53 00:02:49,000 --> 00:02:51,160 ただし例外によります。 54 00:02:51,720 --> 00:02:56,800 ユニットテストをするアジャイルな プログラミングや 55 00:02:57,000 --> 00:03:00,080 テスト駆動なプログラミングで 56 00:03:00,240 --> 00:03:04,440 例外が起こったことをどうやって テストしたら良いでしょう? 57 00:03:04,600 --> 00:03:08,840 shouldnt:raise や should:raise: を使います。 58 00:03:09,000 --> 00:03:10,440 一緒に読んでみましょう。 59 00:03:10,600 --> 00:03:13,640 ここで 60 00:03:13,800 --> 00:03:15,840 2 月の日付を生成する時に 61 00:03:16,000 --> 00:03:18,240 SubscriptOutOfBounds 例外は 62 00:03:18,400 --> 00:03:21,640 挙がって欲しくない、と書きます。 63 00:03:21,800 --> 00:03:25,200 では、13 月の日付を生成する時には 64 00:03:25,360 --> 00:03:29,040 エラーが発生しなければならない とします。 65 00:03:29,200 --> 00:03:32,240 まあ普通はそんな日付はないですね。 66 00:03:32,400 --> 00:03:35,560 そこで should:raise: を使います。 67 00:03:35,720 --> 00:03:37,080 つまり 68 00:03:37,240 --> 00:03:40,960 13 月の日付を作るとエラーになる ということです。 69 00:03:41,120 --> 00:03:44,000 こうすることで例外についての 70 00:03:44,160 --> 00:03:46,280 ユニットテストを書くことができます。 71 00:03:46,440 --> 00:03:48,400 細かなことではありますが 72 00:03:48,560 --> 00:03:51,120 これら 2 つのヘルパーメソッドを 知ることは重要です。 73 00:03:52,120 --> 00:03:54,360 Pharo での例外には 74 00:03:54,560 --> 00:03:56,040 Error があります。 75 00:03:56,200 --> 00:03:59,360 メッセージを理解できない 添字エラー、ゼロ除算など。 76 00:03:59,520 --> 00:04:03,280 Halt があります。 デバッグする時に見ることになります。 77 00:04:03,440 --> 00:04:04,840 ブレークポイントを置いて 78 00:04:05,000 --> 00:04:07,480 システムの実行を止めることができます。 79 00:04:07,640 --> 00:04:10,760 Notification があります。 致命的でないものです。 80 00:04:10,920 --> 00:04:15,400 例えば 廃止(Deprecation)です。 このメソッドは使うな。他のを使えと。 81 00:04:15,560 --> 00:04:16,880 警告やタイムアウトもです。 82 00:04:17,040 --> 00:04:19,760 おもしろいのは 83 00:04:19,920 --> 00:04:22,240 UnhandledError です。 84 00:04:22,400 --> 00:04:25,240 これがデバッガーを起動します。 85 00:04:25,400 --> 00:04:28,680 通常は UnhandledError は使いませんが UnhandledError も Error の一種だと 86 00:04:28,840 --> 00:04:31,360 いうことは知っておいてください。 87 00:04:32,080 --> 00:04:34,720 例外は本物のオブジェクトです。 88 00:04:34,920 --> 00:04:37,920 doesNotUnderstand: メッセージが 89 00:04:38,120 --> 00:04:41,600 ProtoObject でどう定義されているか Pharo ブラウザで見ることができます。 90 00:04:41,760 --> 00:04:43,920 そこでは MessageNotUnderstood new 91 00:04:44,080 --> 00:04:48,960 message: と receiver: を送って signal します。 92 00:04:49,120 --> 00:04:53,480 この例外は Point new strangeAndBizarre で起こります。 93 00:04:53,640 --> 00:04:56,160 strangeAndBizarre メッセージは 知らないので。 94 00:04:56,320 --> 00:04:57,920 そこで例外を作ります。 95 00:04:59,440 --> 00:05:01,880 Deprecationは 例えば 96 00:05:02,040 --> 00:05:05,040 まだ成長している API を使っていて 97 00:05:05,200 --> 00:05:08,200 もう有効ではないと Pharo が決めた場合です。 98 00:05:08,360 --> 00:05:09,520 実際… 99 00:05:09,680 --> 00:05:15,000 Pharo では deprecated:on:in: を使います。 100 00:05:15,160 --> 00:05:17,360 分かりやすい例を選んでみました。 101 00:05:17,520 --> 00:05:19,680 menuItem title: は何を言っているかというと 102 00:05:19,840 --> 00:05:23,880 title: のかわりに addTitle: を使えということです。 103 00:05:25,200 --> 00:05:26,960 どう実装されているかというと 104 00:05:27,120 --> 00:05:30,480 deprecated:... は 105 00:05:30,640 --> 00:05:33,960 Deprecation という 106 00:05:34,120 --> 00:05:35,280 例外を生成して 107 00:05:35,440 --> 00:05:39,960 その例外オブジェクトに メソッドや説明を与えて 108 00:05:40,120 --> 00:05:42,680 signal します。 109 00:05:42,840 --> 00:05:46,800 deprecation も messageNotUnderstood も 例外で、例外を生成して挙げているということです。 110 00:05:48,320 --> 00:05:52,080 これは細かいことになりますが 例外の集合 ExceptionSet もあります。 111 00:05:52,240 --> 00:05:54,960 ZeroDivide や Warning が起こったら という記述ができます。 112 00:05:55,120 --> 00:05:59,080 あるいはコンマで区切ることで 113 00:05:59,240 --> 00:06:02,800 例外の集合を生成することができます。 114 00:06:02,960 --> 00:06:06,200 これを使って これらの例外に反応する、と書けます。 115 00:06:06,360 --> 00:06:11,000 滅多に使われません。 一通り見せるために説明しています。 116 00:06:11,720 --> 00:06:14,840 では、より頻繁に使われる 117 00:06:15,520 --> 00:06:17,320 便利なメソッドを見てみましょう。 118 00:06:17,480 --> 00:06:20,680 ある表現式について プログラムがその手前で失敗しても。 119 00:06:20,840 --> 00:06:24,360 その表現式が必ず実行されるとどうやって 確証を得ることができるでしょうか? 120 00:06:24,520 --> 00:06:27,320 ensure: を使います。 ensure: は 121 00:06:27,480 --> 00:06:29,120 何かをやっていて 122 00:06:29,280 --> 00:06:33,520 別のブロックが実行されることを 保証します。 123 00:06:33,680 --> 00:06:38,800 とても強力です。 例えば自動的にファイルをクローズできます。 124 00:06:39,400 --> 00:06:43,160 Pharo のプロファイラーの spyOn: を見てみましょう。 125 00:06:43,320 --> 00:06:46,680 プロファイリングを開始して 126 00:06:46,840 --> 00:06:49,640 プロファイリング対象の このブロックを実行します。 127 00:06:49,800 --> 00:06:52,160 そしてプロファイルを停止することを 保証します。 128 00:06:52,320 --> 00:06:55,200 たとえプロファイル対象として渡された ブロックがエラーを起こしても。 129 00:06:55,400 --> 00:06:57,480 もう1つ、とても便利なヘルパーがあります。 130 00:06:57,680 --> 00:07:00,000 ある表現式が 131 00:07:00,160 --> 00:07:04,680 プログラムが失敗した時だけ 実行されることを保証します。 132 00:07:05,440 --> 00:07:09,320 何か変なことが起こったら 133 00:07:09,480 --> 00:07:13,880 これを実行する、というものです。 134 00:07:14,040 --> 00:07:16,680 wait の例は低レベルのもので 135 00:07:16,840 --> 00:07:20,800 プロセッサーのスケジューリングを 変えるものです。 136 00:07:21,520 --> 00:07:26,800 システムがセマフォをスケジュールして 137 00:07:26,960 --> 00:07:30,320 何か不具合があったら 138 00:07:30,480 --> 00:07:32,520 システムがスケジューラから 139 00:07:32,680 --> 00:07:36,160 外すことを保証します。 140 00:07:36,320 --> 00:07:40,080 これらのメソッドは とても手軽でパワフルです。 141 00:07:40,480 --> 00:07:45,280 メソッド探索がどう動くかを説明する 142 00:07:45,440 --> 00:07:47,120 スライドを 143 00:07:47,320 --> 00:07:48,480 お見せしましたが 144 00:07:48,680 --> 00:07:50,440 ここでは... 145 00:07:50,600 --> 00:07:53,600 Pharo での例外では 146 00:07:53,760 --> 00:07:59,160 別の結果を返したり 再実行したりできます。 147 00:07:59,320 --> 00:08:01,320 プログラムの実行を変更して 148 00:08:01,480 --> 00:08:05,320 例外が起こらなかったかのように 動くようにすることが 149 00:08:05,480 --> 00:08:07,800 resume を使ってできます。 150 00:08:07,960 --> 00:08:11,600 この例外はこのレベルでは扱いたくないから 151 00:08:11,760 --> 00:08:13,280 より上位で扱ってほしい、ということが 152 00:08:13,440 --> 00:08:14,920 例外を pass することで可能です。 153 00:08:15,080 --> 00:08:18,840 古い例外を新しい例外で置き換えることも 154 00:08:19,000 --> 00:08:19,880 resignal でできます。 155 00:08:20,040 --> 00:08:23,520 これが必要な時には あなたは何をやっているか分かっているでしょう。 156 00:08:23,680 --> 00:08:28,400 この章を読んで こういうことができるこということを 157 00:08:28,600 --> 00:08:30,520 知っておいてください。 158 00:08:30,720 --> 00:08:33,600 例外から別の返り値を返す時は return: を使います。 159 00:08:33,760 --> 00:08:38,160 これを見てわかるように この値を返すブロックを渡して 160 00:08:38,320 --> 00:08:41,400 例外を挙げると、最終的には 161 00:08:41,560 --> 00:08:45,400 ブロックが返したこの値が返ってきます。 これが return: です。 162 00:08:45,560 --> 00:08:48,400 では、resume: は何かというと 163 00:08:48,560 --> 00:08:50,920 resume: では 164 00:08:51,080 --> 00:08:54,240 ここで起こされた例外について 165 00:08:54,400 --> 00:08:58,560 resume: すると 166 00:08:58,720 --> 00:09:02,120 このハンドラで与えた値ではなく 次の値になります。 167 00:09:02,280 --> 00:09:07,360 例外が発生した箇所から継続するのです。 なので、ここから再開します。 168 00:09:07,520 --> 00:09:10,120 そしてこの値が得られます。 169 00:09:11,240 --> 00:09:14,000 ではまとめます。 170 00:09:14,200 --> 00:09:16,960 Pharo の例外は強力です。 ええ、いいですね。 171 00:09:17,120 --> 00:09:20,840 とてもシンプルな API があります。 例外を挙げる signal と 172 00:09:21,000 --> 00:09:22,720 例外を捕捉する on:do: と 173 00:09:22,880 --> 00:09:27,880 この表現式が必ず実行されるように 保証する ensure: と 174 00:09:28,040 --> 00:09:30,280 問題が発生するか否かで 175 00:09:30,440 --> 00:09:32,720 発生した時に実行する ifCurtailed: 176 00:09:32,880 --> 00:09:35,720 doSomething の中で問題が発生したら onProblem を実行します。 177 00:09:35,880 --> 00:09:38,760 例外を使い始めるために必要なことは これで全てです。