﻿1
00:00:00,480 --> 00:00:04,600
このビデオでは Pharo の先進的な
側面に注目します。

2
00:00:04,800 --> 00:00:10,800
ライブプログラミングに必要な
リフレクティブな操作です。

3
00:00:11,680 --> 00:00:16,680
クラスを再コンパイルする時に
何が起きるのかを見ていきましょう。

4
00:00:17,040 --> 00:00:20,080
そしてライブプログラミングを
実践するために

5
00:00:20,200 --> 00:00:24,720
必要なリフレクティブな操作を
説明します。

6
00:00:24,920 --> 00:00:26,560
ここに典型例があります。

7
00:00:26,720 --> 00:00:30,320
我々は通常はまずクラスを定義して

8
00:00:30,600 --> 00:00:34,640
それからメソッドを追加して
そのクラスのインスタンスを作ります。

9
00:00:35,160 --> 00:00:40,400
そしてクラスを再定義して
新しいインスタンス変数を追加します。

10
00:00:41,200 --> 00:00:45,640
では、属性が 1 つ減ったら

11
00:00:46,160 --> 00:00:48,440
既に存在しているインスタンスは
どうなるのでしょう？

12
00:00:48,680 --> 00:00:53,920
元のインスタンスを新しいクラスに
マイグレーションする

13
00:00:54,280 --> 00:00:57,360
メカニズムが必要です。

14
00:00:57,640 --> 00:00:59,160
それで動き続けます。

15
00:00:59,600 --> 00:01:03,200
クラスの動的な再定義や
メソッドの再コンパイルを可能にして

16
00:01:04,440 --> 00:01:09,160
インスタンスを新しいバージョンのクラスに

17
00:01:09,600 --> 00:01:11,040
自動的かつ透過的に

18
00:01:11,400 --> 00:01:15,160
マイグレーションさせるための

19
00:01:15,360 --> 00:01:18,200
操作を見ていきます。

20
00:01:18,520 --> 00:01:22,560
そのためにはまず、特定のクラスの
全てのインスタンスを得る必要があります。

21
00:01:22,840 --> 00:01:28,280
それから、それらのオブジェクトを
指していたポインタを

22
00:01:28,840 --> 00:01:31,920
新しいオブジェクトを指すように
全て置き換えていきます。

23
00:01:32,400 --> 00:01:33,400
いいですか？

24
00:01:34,160 --> 00:01:38,920
まずは、あるクラスの全てのインスタンスを
どうやって集めてくるかです。

25
00:01:39,400 --> 00:01:43,560
クラスに
allInstances メッセージを送ると

26
00:01:43,800 --> 00:01:47,320
その全てのインスタンスが得られます。

27
00:01:47,640 --> 00:01:51,440
通常のオブジェクトのコレクションです。

28
00:01:51,640 --> 00:01:57,800
Window クラスに送れば
Window オブジェクトのコレクションが得られます。

29
00:01:58,280 --> 00:02:02,760
最初の要素を取り出して
close メッセージを送ることができます。

30
00:02:02,920 --> 00:02:06,840
close メソッドは Window クラスで
定義されているので。

31
00:02:07,360 --> 00:02:11,840
リフレクティブなプリミティブには
pointersTo もあります。

32
00:02:12,160 --> 00:02:16,920
このメッセージをオブジェクトに送ると
そのオブジェクトへの参照を持つ

33
00:02:17,400 --> 00:02:21,000
全てのオブジェクトのコレクションを
得ることができます。

34
00:02:21,200 --> 00:02:23,040
オブジェクトを入れ替えたい時には

35
00:02:23,200 --> 00:02:27,320
とても便利です。

36
00:02:29,560 --> 00:02:34,080
ポインタを入れ替えるプリミティブは
become: です。

37
00:02:34,600 --> 00:02:39,760
2 つのオブジェクトを
入れ替えることができます。

38
00:02:41,160 --> 00:02:43,840
2 つのオブジェクトを対称的に入れ替えます。

39
00:02:44,200 --> 00:02:48,200
システム中のこのオブジェクトを指す全て

40
00:02:48,720 --> 00:02:51,160
この場合は ポインタが 2 つですが

41
00:02:51,360 --> 00:02:55,840
それらは、このオブジェクトを指すように
置き換えられます。

42
00:02:57,280 --> 00:03:01,720
こちら側のポインタは全て破棄されて

43
00:03:02,280 --> 00:03:04,080
オブジェクトが入れ替えられます。

44
00:03:06,360 --> 00:03:11,680
become: はシステム中のポインタを
対称的に入れ替えるということです。

45
00:03:13,280 --> 00:03:15,080
ここに例題があります。

46
00:03:15,320 --> 00:03:17,600
pt1 は

47
00:03:17,800 --> 00:03:22,320
点オブジェクト 0@0 を指して
変数 pt2 も

48
00:03:22,840 --> 00:03:25,320
その 0@0 オブジェクトを指します。

49
00:03:25,560 --> 00:03:29,560
さらに、変数 pt3 は
点 100@100 を指します。

50
00:03:29,800 --> 00:03:33,200
そして、pt1 become: pt3 と書きます。

51
00:03:34,160 --> 00:03:38,680
変数 pt1 として示されるこのオブジェクト
を指していたものは

52
00:03:38,920 --> 00:03:41,440
pt3 を指すようになりました。

53
00:03:42,200 --> 00:03:44,400
つまり、pt1 への全てのポインタが
pt3 を指しています。

54
00:03:44,600 --> 00:03:49,760
変数 pt2 は pt1 と同じオブジェクトを
指していましたが

55
00:03:49,920 --> 00:03:54,400
pt3 で参照されていたオブジェクトを
指しています。

56
00:03:54,760 --> 00:04:00,440
pt3 については、対称的なので
pt1 が指していたオブジェクトを指します。

57
00:04:00,640 --> 00:04:01,760
一番上のものです。

58
00:04:02,800 --> 00:04:06,080
そして pt1 は pt3 だったものを
指しています。

59
00:04:06,280 --> 00:04:10,000
つまり、ポインタが
対称的に入れ替わりました。

60
00:04:11,200 --> 00:04:14,800
非対称な入れ替えは
becomeForward: です。

61
00:04:15,440 --> 00:04:18,400
ポインタの入れ替えをするのですが

62
00:04:18,640 --> 00:04:23,360
このオブジェクトを指していたものは
こちらのオブジェクトに置き換わり

63
00:04:24,080 --> 00:04:28,400
逆には働きません。
このオブジェクトへのポインタはそのままです。

64
00:04:31,520 --> 00:04:34,640
別の例があります。

65
00:04:35,280 --> 00:04:39,640
becomeForward: を実行すると

66
00:04:39,920 --> 00:04:45,080
pt1 と pt2 に影響が出ます。

67
00:04:45,600 --> 00:04:48,640
pt3 は becomeForard: の
影響を受けません。

68
00:04:48,840 --> 00:04:53,000
このオブジェクトを指していたものは
変化しません。

69
00:04:55,400 --> 00:04:59,840
また別のリフレクティブなプリミティブに
adoptInstance: があります。

70
00:05:00,200 --> 00:05:02,640
これはオブジェクトのクラスを入れ替えます。

71
00:05:02,840 --> 00:05:07,920
引数として渡されたインスタンスを
クラスに「引き取る」ように頼みます。

72
00:05:08,560 --> 00:05:13,400
クラスを変更することはとても強力な
道具ですが、制限もあります。

73
00:05:13,640 --> 00:05:17,520
そのオブジェクト

74
00:05:18,160 --> 00:05:19,840
この場合 anInstance ですが
このオブジェクトの元のクラスが

75
00:05:20,040 --> 00:05:24,680
新しいクラスのフォーマットと
互換性があることが必須条件です。

76
00:05:25,440 --> 00:05:29,160
どんなオブジェクトも入れ替える
というわけにはいきません。

77
00:05:29,360 --> 00:05:31,840
インデックス付き、などなど

78
00:05:32,080 --> 00:05:36,000
オブジェクトのフォーマットは
とても重要です。

79
00:05:36,680 --> 00:05:40,640
クラスとは何かというと

80
00:05:40,920 --> 00:05:43,360
クラスは本質的にはフォーマットです。

81
00:05:43,640 --> 00:05:47,200
フォーマットがインスタンス変数の数や

82
00:05:47,400 --> 00:05:52,520
可変領域の型を規定します。
前の講義で説明しましたね。

83
00:05:52,840 --> 00:05:56,000
クラスはスーパークラスや
メソッド辞書を持っています。

84
00:05:56,840 --> 00:06:01,680
Behavior クラスがあります。
これは Class クラスのスーパークラスで

85
00:06:02,080 --> 00:06:07,520
クラスの基本的な振る舞いを定義しています。

86
00:06:08,160 --> 00:06:11,000
クラスの最小限の基本機能です。

87
00:06:11,200 --> 00:06:14,720
クラスはスーパークラスと
メソッド辞書と

88
00:06:14,840 --> 00:06:18,200
フォーマットを持っています。

89
00:06:19,200 --> 00:06:24,440
ここまで話してきた
リフレクティブな振る舞いの機能を

90
00:06:25,000 --> 00:06:27,360
具体的な例を挙げながら

91
00:06:28,440 --> 00:06:33,440
まとめてみましょう。

92
00:06:34,760 --> 00:06:37,800
それに沿ってコードを説明していきます。

93
00:06:38,000 --> 00:06:42,400
これらの 3 行で
Behavior クラスのインスタンスを作ります。

94
00:06:42,640 --> 00:06:44,280
いいですか、クラスですよ。

95
00:06:44,640 --> 00:06:50,080
Behavior という名前のクラスの
インスタンスを作ります。

96
00:06:51,600 --> 00:06:54,400
これを behavior と呼ぶことにします。

97
00:06:55,040 --> 00:07:00,600
このオブジェクトは Model クラスを
継承するように記述します。

98
00:07:02,000 --> 00:07:03,000
こんな風に。

99
00:07:03,680 --> 00:07:08,080
この behavior オブジェクトの
フォーマットを設定します。

100
00:07:08,600 --> 00:07:12,400
そして Model クラスのインスタンスを
生成します。

101
00:07:14,520 --> 00:07:16,360
このオブジェクトを model とします。

102
00:07:17,200 --> 00:07:20,080
ここ、このコードのこの行が重要です。

103
00:07:20,760 --> 00:07:23,920
model オブジェクトのクラスを

104
00:07:24,080 --> 00:07:28,920
引数として渡したクラス
つまり behavior に変更します。

105
00:07:29,200 --> 00:07:34,400
それまでのインスタンス関係のリンクを切って
このクラスのインスタンスにします。

106
00:07:34,800 --> 00:07:37,400
このクラスは
Model クラスのサブクラスです。

107
00:07:38,800 --> 00:07:43,400
さて、ここでこのクラスの
新しいメソッドをコンパイルします。

108
00:07:43,600 --> 00:07:47,400
メソッド foo は 2 を返します。
これをコンパイルします。

109
00:07:48,840 --> 00:07:51,840
behavior オブジェクトで。

110
00:07:53,560 --> 00:07:55,280
見ての通り

111
00:07:55,560 --> 00:07:59,840
ここの model オブジェクトに
foo メッセージを

112
00:08:01,000 --> 00:08:02,160
こんな風に送ると

113
00:08:02,760 --> 00:08:04,160
2 が返ってきます。

114
00:08:04,640 --> 00:08:06,720
この部分はメソッド探索についてです。

115
00:08:07,400 --> 00:08:09,040
foo メッセージを送ります。

116
00:08:09,200 --> 00:08:14,600
model オブジェクトはそのクラスつまり
behavior オブジェクトで探索します。

117
00:08:14,800 --> 00:08:17,360
そしてメソッドが見つかります。

118
00:08:17,760 --> 00:08:19,160
完璧に動作します。

119
00:08:19,920 --> 00:08:24,080
しかし Model クラスのインスタンスを

120
00:08:25,200 --> 00:08:26,200
このようにして作って

121
00:08:26,560 --> 00:08:28,360
foo メッセージを送っても

122
00:08:29,360 --> 00:08:33,360
MessageNotUnderstood エラーが
発生します。

123
00:08:33,640 --> 00:08:35,800
メソッド探索が

124
00:08:36,080 --> 00:08:39,080
そのオブジェクトのクラス
つまり Model クラスから探すからです。

125
00:08:39,320 --> 00:08:43,920
foo メソッドは Model クラスや
スーパークラスのメソッド辞書では見つかりません。

126
00:08:45,040 --> 00:08:51,040
この高度なメカニズムを使うと
Model クラスの特定のインスタンスにだけ

127
00:08:51,520 --> 00:08:54,040
振る舞いを与えることができます。

128
00:08:54,200 --> 00:08:57,840
わかりやすくするために、このやり方を
Set クラスにも適用してみましょう。

129
00:08:58,040 --> 00:09:01,280
Set クラスのインスタンス set1 を
生成します。

130
00:09:01,800 --> 00:09:05,720
Set クラスのメソッド辞書には
add: メソッドがあります。

131
00:09:06,400 --> 00:09:11,520
Set クラスの特定のインスタンスにだけ
add: メソッドを変更したいとします。

132
00:09:11,720 --> 00:09:15,360
特定のインスタンスに
特定の振る舞いということです。

133
00:09:15,520 --> 00:09:18,400
そこで匿名のクラスを作ります。

134
00:09:18,840 --> 00:09:22,920
Set クラスを継承します。

135
00:09:23,280 --> 00:09:25,200
ここにその継承関係があります。

136
00:09:25,600 --> 00:09:31,160
set2 オブジェクトは
この匿名クラスのインスタンスです。

137
00:09:31,720 --> 00:09:37,000
その匿名クラスのメソッド辞書で
add: メソッドを

138
00:09:37,320 --> 00:09:40,640
set2 に特定の振る舞いで再定義します。

139
00:09:40,920 --> 00:09:45,800
ここで add: メッセージを
set2 オブジェクトに送ります。

140
00:09:46,080 --> 00:09:48,400
すると本来とは異なる別の振る舞いをします。

141
00:09:48,800 --> 00:09:52,320
この set1 にメッセージを送っていたら

142
00:09:53,600 --> 00:09:58,040
このメソッドが選択されていたでしょうが
それとは異なる振る舞いをします。

143
00:09:58,280 --> 00:10:03,360
つまり、これら 2 つの集合は
add: メッセージに別々の反応をします。

144
00:10:03,680 --> 00:10:07,080
ここに演習問題となるコードがあります。

145
00:10:07,400 --> 00:10:11,280
さきほどと同様に
Behavior クラスのインスタンスとして

146
00:10:11,640 --> 00:10:13,800
クラスを作ります。

147
00:10:14,080 --> 00:10:16,840
スーパークラスを Set クラスとします。

148
00:10:17,400 --> 00:10:18,640
フォーマットを設定します。

149
00:10:18,840 --> 00:10:23,600
この匿名クラスで
add: メソッドをコンパイルします。

150
00:10:24,080 --> 00:10:29,360
これで Set クラスで定義されている
add: メソッドを再定義します。

151
00:10:30,080 --> 00:10:36,080
Transcript show を使って
add: メソッドの実行を表示します。

152
00:10:36,400 --> 00:10:40,680
それから super を使って
Set クラスでの add: メソッドを実行します。

153
00:10:41,360 --> 00:10:45,720
では、1 つ目の集合を作って
テストしてみましょう。

154
00:10:45,920 --> 00:10:48,600
Set クラスはここにあります。

155
00:10:50,280 --> 00:10:54,280
このクラスの最初のインスタンスを生成して
set とします。

156
00:10:55,080 --> 00:10:57,040
そのオブジェクトに
add: メッセージを送ります。

157
00:10:58,920 --> 00:11:03,760
Set クラスの add: メソッドが
使われます。

158
00:11:05,240 --> 00:11:08,720
ここで set のクラスを尋ねると
Set が得られます。

159
00:11:09,400 --> 00:11:13,160
しかし、ここでこのプリミティブを
実行します。

160
00:11:13,600 --> 00:11:16,200
set オブジェクトのクラスを変更して

161
00:11:16,400 --> 00:11:21,160
前の方で Behavior クラスを使って

162
00:11:22,080 --> 00:11:23,760
Set クラスのサブクラスにします。

163
00:11:24,360 --> 00:11:28,400
これでクラスが変更されて
add: メソッドの新しいバージョンを持った

164
00:11:28,680 --> 00:11:32,000
logClass のインスタンスになります。

165
00:11:32,280 --> 00:11:37,920
ここで、このオブジェクトに
add: 2 メッセージを送ります。

166
00:11:38,360 --> 00:11:43,280
するとこの add: メソッドが選ばれて

167
00:11:43,560 --> 00:11:45,720
このコードが実行されます。

168
00:11:46,280 --> 00:11:48,920
Transcript を見て

169
00:11:49,760 --> 00:11:53,280
このメソッドが実行されたか確認できます。

170
00:11:53,640 --> 00:11:57,400
2 は追加されます。

171
00:11:57,640 --> 00:12:02,040
super を使って Set クラスの
add: メソッドを使うからです。

172
00:12:02,840 --> 00:12:07,840
こうして特定の集合を
スパイすることができます。

173
00:12:08,080 --> 00:12:09,560
この行を使って。

174
00:12:11,200 --> 00:12:12,400
まとめると

175
00:12:12,600 --> 00:12:19,200
これらのリフレクティブな操作を使って
とても画期的なツールを作ることができます。

176
00:12:19,440 --> 00:12:23,840
新しい機能を実装して
テストすることができます。

177
00:12:24,080 --> 00:12:29,400
これらのリフレクティブなプリミティブで
言語拡張をすることができます。

178
00:12:30,200 --> 00:12:34,080
ただし、リフレクションを使う上での
黄金律があります。

179
00:12:34,320 --> 00:12:38,800
ドメインコードで不適切な使い方を
してはいけない、ということです。

180
00:12:39,040 --> 00:12:44,720
ドメインコードでリフレクティブなコードを
使うことは制限すべきです。

181
00:12:45,080 --> 00:12:49,200
リフレクションを使うと
カプセル化を破ることができます。

182
00:12:49,840 --> 00:12:51,000
本当に

183
00:12:51,440 --> 00:12:54,640
オブジェクトプログラミングの規律を
踏み越えることができてしまいます。

184
00:12:54,840 --> 00:12:58,520
したがって、ツール構築に使うに
留めておくべきです。
