﻿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 のこの高度な機能を
いじり回してみましょう。
