1 00:00:00,560 --> 00:00:04,040 この講義では高度な機能を もう 1 つ探検します。 2 00:00:04,200 --> 00:00:07,080 オンデマンドで実行スタックを 3 00:00:07,280 --> 00:00:10,560 オブジェクトに変換する方法を 見せたいと思います。 4 00:00:11,200 --> 00:00:15,600 あまり細部には触れません。 直感的な道具立てとするのが目的です。 5 00:00:17,080 --> 00:00:19,840 スタックを操作して ナビゲーションしたり 6 00:00:20,040 --> 00:00:23,160 変更したりできますが 今回はナビゲーションに焦点を合わせます。 7 00:00:23,600 --> 00:00:28,400 この話題についての読み物として 本の中で 2 つの章があります。 8 00:00:28,640 --> 00:00:31,640 ブロックに関する章と 9 00:00:31,840 --> 00:00:35,080 例外に関する章が Deep into Pharo という本にあります。 10 00:00:35,280 --> 00:00:39,280 明快な説明がされていて 読む価値があるものです。 11 00:00:39,520 --> 00:00:43,400 Pharo では Context クラスも スタックを表現します。 12 00:00:44,600 --> 00:00:45,600 さてと 13 00:00:46,280 --> 00:00:50,160 デバッガの中でコーディングする シナリオを使います。 14 00:00:50,400 --> 00:00:55,000 ユニットテストを実行した時に 15 00:00:55,200 --> 00:00:57,520 送ったメッセージが未定義のために 見つからなかったとします。 16 00:00:57,840 --> 00:01:02,720 そのメソッドを作るように デバッガに言って 17 00:01:02,920 --> 00:01:06,040 コンパイルして クラスにインストールします。 18 00:01:06,200 --> 00:01:07,920 そして再実行します。 19 00:01:08,080 --> 00:01:12,560 このメソッドは例外を上げます。 このシステムは魔法ではないので。 20 00:01:12,720 --> 00:01:16,200 shouldBeImplemented メッセージが 21 00:01:16,360 --> 00:01:19,440 デバッガでそのメソッドを編集するように 促してきます。 22 00:01:19,640 --> 00:01:21,440 そのメソッドを実装して 23 00:01:21,840 --> 00:01:26,000 その場で再コンパイルして 「Proceed」を選んで 24 00:01:26,600 --> 00:01:28,080 プログラムを継続実行させます。 25 00:01:28,920 --> 00:01:32,360 このシナリオには 2 つのキーポイントがあります。 26 00:01:32,920 --> 00:01:36,280 1 つ目は、メソッドをオンザフライで 再コンパイルしたこと。 27 00:01:36,640 --> 00:01:40,080 何度もやりますが それはコンパイラの仕事です。 28 00:01:40,920 --> 00:01:44,920 2 つ目は、これが重要ですが 実行スタックを書き換えて 29 00:01:45,080 --> 00:01:48,840 スタック上に 新しいチャンクを挿入します。 30 00:01:49,040 --> 00:01:53,200 そうすることでエラーの後でも プログラムを継続実行できます。 31 00:01:53,440 --> 00:01:58,600 単にスタックを具体化(レイフィケーション) してオブジェクトにするだけでなく 32 00:01:58,760 --> 00:02:03,640 形の上での演習でもなく ユーザ体験を向上させたり 33 00:02:03,920 --> 00:02:05,560 新しいツールを作ることができます。 34 00:02:05,720 --> 00:02:10,640 ウェブアプリケーションを作る Seaside でも使われています。 35 00:02:11,080 --> 00:02:15,720 Pharo は通常は C のスタックを持っています。 仮想機械のスタックです。 36 00:02:16,040 --> 00:02:19,360 オンデマンドで、これを ライブなオブジェクトに変換します。 37 00:02:19,520 --> 00:02:25,440 興味深いのは、これを使って ナビゲーションしたり修正できるのです。 38 00:02:25,760 --> 00:02:30,200 ここでいう修正とは この Pharo のオブジェクトを変化させると 39 00:02:30,400 --> 00:02:34,400 直接手の届かない C のスタックも変化させる とても強力なものです。 40 00:02:35,800 --> 00:02:41,280 例外処理にも対応しています。 ぜひこれらの章を読むことを勧めます。 41 00:02:41,560 --> 00:02:44,080 例外に対してスタックを辿っていって 42 00:02:44,440 --> 00:02:47,920 キャッチブロックを探します。 43 00:02:49,920 --> 00:02:51,800 いわゆる例外ハンドラです。 44 00:02:52,000 --> 00:02:57,200 さらに、スタックをオブジェクトに 変換する能力は 45 00:02:57,400 --> 00:02:59,840 Scheme のような 関数型言語にある継続や 46 00:03:00,040 --> 00:03:04,400 ウェブサービスを可能にします。 47 00:03:05,320 --> 00:03:09,080 どうやって動くのか説明するために thisContext と呼ばれる変数を見ます。 48 00:03:09,200 --> 00:03:13,640 Pharo の 3 つの擬似変数の 1 つです。 49 00:03:14,160 --> 00:03:17,360 擬似変数は self と super と thisContext です。 50 00:03:17,920 --> 00:03:22,600 thisContext の値を得ようとすると 実行スタックが返ってきます。 51 00:03:22,920 --> 00:03:27,400 デバッガを開くと見えるものです。 52 00:03:27,640 --> 00:03:31,840 実行スタックは thisContext に基づいて表示されます。 53 00:03:32,200 --> 00:03:36,280 halt を挿入した 54 00:03:36,400 --> 00:03:39,360 メソッドを定義すると 55 00:03:39,520 --> 00:03:44,400 デバッガが開きます。 しかし、thisContext と入力して 56 00:03:45,440 --> 00:03:50,040 インスペクターを開いても 実行スタックそのものが開きます。 57 00:03:50,600 --> 00:03:53,800 thisContext を使う例を 58 00:03:53,920 --> 00:03:56,400 2 つお見せしましょう。 59 00:03:56,680 --> 00:04:02,360 1 つ目はデプリケーションです。 API を変更したい時に使います。 60 00:04:02,640 --> 00:04:08,560 プログラマはメソッドで deprecated: メッセージを 61 00:04:08,720 --> 00:04:13,640 on:in: 付きで使います。 例外の講義で説明しました。 62 00:04:14,680 --> 00:04:19,760 ここでは、「Use bar」という メッセージを示したいわけですが 63 00:04:20,080 --> 00:04:23,840 デプリケーションは 64 00:04:24,000 --> 00:04:26,840 ユーザに 65 00:04:27,040 --> 00:04:30,200 「Message foo is deprecated in Pharo.」 と表示します。 66 00:04:30,360 --> 00:04:33,920 ここで大事な点は 67 00:04:34,200 --> 00:04:36,600 どのメソッドがデプリケーションの対象か 宣言しなかってにも関わらず 68 00:04:36,840 --> 00:04:40,920 deprecated: を呼び出したのは foo だとシステムが特定したことです。 69 00:04:42,080 --> 00:04:46,640 見ての通り、deprecated:の引数には メソッドを呼び出している 70 00:04:47,320 --> 00:04:48,920 foo は与えられていません。 71 00:04:49,080 --> 00:04:51,840 では、どうやって実装されているのでしょう? 72 00:04:52,600 --> 00:04:54,280 deprecated: メッセージは 73 00:04:55,920 --> 00:04:58,040 Deprecation 例外をあげます。 74 00:04:58,200 --> 00:05:03,160 引数として anExplanationString などを渡します。 75 00:05:03,320 --> 00:05:07,800 そして、この表現式が追加されています。 thisContext sender method 76 00:05:08,160 --> 00:05:13,920 thisContext は deprecated: メソッドを 実行中のスタックです。 77 00:05:15,720 --> 00:05:19,320 そして sender を使って メソッドを呼び出した側にアクセスできます。 78 00:05:20,000 --> 00:05:23,200 すると foo が得られます。 つまりこの例題です。 79 00:05:23,600 --> 00:05:25,560 そしてメソッドを求めます。 80 00:05:25,720 --> 00:05:29,800 thisContext sender method はコンパイル済みのメソッドを返します。 81 00:05:29,920 --> 00:05:31,640 それはオブジェクトで 82 00:05:31,800 --> 00:05:35,080 A>>foo という名前です。 83 00:05:35,280 --> 00:05:39,720 こうしてこの例外は メソッドのセレクタを得て 84 00:05:39,920 --> 00:05:43,840 より明確なメッセージを作ります。 85 00:05:44,280 --> 00:05:49,600 プログラマにそのメッセージの元を ハードコードさせることなく 86 00:05:49,800 --> 00:05:54,040 ユーザーが理解しやすい メッセージを作ることができます。 87 00:05:54,320 --> 00:05:59,040 では、もう 1 つの 強力な機能をお見せしましょう。 88 00:06:01,640 --> 00:06:05,280 デバッグをしている時には 激しく使われているメソッドに 89 00:06:05,400 --> 00:06:08,760 ブレークポイントを挿入することが よくあります。 90 00:06:09,360 --> 00:06:13,320 システム全体を止めることなしに 91 00:06:13,440 --> 00:06:15,720 自分のプログラムだけをデバッグ したいわけです。 92 00:06:15,920 --> 00:06:21,040 haltOnce のような条件は システムを一度だけ停止させますが 93 00:06:21,200 --> 00:06:25,680 やりたいことはそうではなく そのメソッドがある別のメソッドから 94 00:06:25,920 --> 00:06:29,000 呼ばれた時だけ halt したいわけです。 95 00:06:29,640 --> 00:06:32,840 プログラマは どう表現したらいいでしょう? 96 00:06:33,040 --> 00:06:37,400 testSetInitialized メソッドから 97 00:06:37,600 --> 00:06:40,520 foo が呼ばれたならば halt というわけです。 98 00:06:41,520 --> 00:06:44,280 どう実装されているのでしょう。 99 00:06:44,440 --> 00:06:47,200 通常、このメソッドは停止してはいけません。 100 00:06:47,760 --> 00:06:52,760 Pharo でコードを開いて どう実装されているか見ることができます。 101 00:06:52,920 --> 00:06:54,840 Halt は例外クラスです。 102 00:06:55,400 --> 00:06:57,640 if: メッセージを見ます。 103 00:06:57,840 --> 00:07:00,160 引数の場合分けがいくつかあります。 104 00:07:00,320 --> 00:07:05,080 シンボルの場合について まずシンボルかどうか問い合わせた上で 105 00:07:05,320 --> 00:07:10,200 コールチェインの中にそのシンボルが 含まれていないかを見ます。 106 00:07:10,400 --> 00:07:11,400 では確認してみましょう。 107 00:07:12,360 --> 00:07:15,360 そのメソッドを見てみます。 108 00:07:16,000 --> 00:07:19,800 testSetInitialized という名前の 109 00:07:20,840 --> 00:07:22,200 テストがあるとします。 110 00:07:23,800 --> 00:07:25,280 その名前がここの引数です。 111 00:07:26,200 --> 00:07:31,400 まず、メソッドは実行スタック 112 00:07:32,720 --> 00:07:35,560 つまりコンテキストを引き出します。 113 00:07:35,760 --> 00:07:41,080 コンテキストを使って スタックにアクセスします。 114 00:07:41,200 --> 00:07:44,920 今は実行スタックの トップではありません。 115 00:07:45,160 --> 00:07:48,080 トップでは呼び出す側の センダーがありません。 116 00:07:48,440 --> 00:07:52,280 スタックのトップでは センダーは nil になります。 117 00:07:52,600 --> 00:07:56,160 センダーが nil ではない場合には 118 00:07:56,520 --> 00:07:59,400 スタックを移動していきます。 119 00:07:59,560 --> 00:08:02,920 スタックの領域を絵に描くと こんな感じになっていて 120 00:08:03,200 --> 00:08:06,040 sender を使って 上のほうにいきます。 121 00:08:06,840 --> 00:08:07,920 1 つずつ。 122 00:08:09,080 --> 00:08:12,080 ここでセレクターを 見ていく必要があります。 123 00:08:12,200 --> 00:08:15,520 この領域のどこかに テストがあるはずです。 124 00:08:16,680 --> 00:08:18,320 もしスタックのコールシンボルが 125 00:08:18,840 --> 00:08:23,080 停止対象にしたいものと マッチしているか見ていきます。 126 00:08:23,200 --> 00:08:26,400 testSet…から呼ばれていないか チェックしていきます。 127 00:08:26,640 --> 00:08:31,200 該当していたら、そこで signal します。 このクラスは例外クラスですから。 128 00:08:32,000 --> 00:08:36,320 重要なのは、スタックの具体化を しない言語でこれを実装することは 129 00:08:36,440 --> 00:08:39,760 難しいということを 理解することです。 130 00:08:40,080 --> 00:08:44,640 ここでは 5 行です。理解するのは 大変そうに見えるかもしれませんが。 131 00:08:44,840 --> 00:08:49,560 コンパクトで強力で 具体化を通してのみ可能なのです。 132 00:08:50,160 --> 00:08:55,640 thisContext は高度な機能なので 多くは使われません。 133 00:08:55,920 --> 00:08:59,160 しかしツールなど新しいものを 創造する上で重要なものです。 134 00:08:59,320 --> 00:09:02,080 これらのテストで見たように 135 00:09:02,840 --> 00:09:05,560 この言語ではサポートされています。 136 00:09:05,720 --> 00:09:09,080 継続を表現するためにも使われます。 137 00:09:09,400 --> 00:09:12,600 Seaside を創った人は 継続を表現するために 138 00:09:12,760 --> 00:09:16,280 スタックを操作するために Pharo の先祖にあたる言語を使いました。 139 00:09:16,400 --> 00:09:21,840 これは Seaside のコールアンサーの 基礎になっています。 140 00:09:22,280 --> 00:09:27,280 Pharo のこの高度な機能を いじり回してみましょう。