﻿1
00:00:00,400 --> 00:00:03,560
こんにちは。この講義では
リフレクションを見ていきます。

2
00:00:03,720 --> 00:00:08,640
Pharo 自身の中を見て
リフレクションの利用法を見ていきましょう。

3
00:00:09,600 --> 00:00:11,880
リフレクションは

4
00:00:12,040 --> 00:00:15,960
大きく 2 つに分類できます。

5
00:00:16,120 --> 00:00:18,000
イントロスペクションは

6
00:00:18,160 --> 00:00:21,240
プログラムが自身の状態を観察する
能力のことです。

7
00:00:21,400 --> 00:00:25,880
インターセッションはプログラムが
自分自身を修正する能力です。

8
00:00:26,040 --> 00:00:29,040
レイフィケーションは

9
00:00:30,640 --> 00:00:34,560
自身の状態や実行を変更するために

10
00:00:34,720 --> 00:00:39,760
通常は暗黙になっているものを
明示化する概念です。

11
00:00:39,920 --> 00:00:43,920
例えば、Pharo では

12
00:00:44,080 --> 00:00:49,400
実行スタックは明示的です。
古典的なオブジェクトとして表現されます。

13
00:00:49,920 --> 00:00:55,280
Pharo ではクラスも
完全に古典的なオブジェクトです。

14
00:00:55,480 --> 00:00:58,960
他の言語には
クラスはオブジェクトではないものもあります。

15
00:01:00,040 --> 00:01:02,160
リフレクションのあるシステムでは

16
00:01:02,320 --> 00:01:06,600
それ自身の表現を得ることができます。

17
00:01:06,760 --> 00:01:09,600
それ自身を表現することができ

18
00:01:09,760 --> 00:01:14,840
その表現を使ってそれ自身を変更できます。

19
00:01:15,000 --> 00:01:19,600
表現を変更した時
そのシステムの状態を変更します。

20
00:01:19,760 --> 00:01:22,600
それを因果関係と呼びます。

21
00:01:22,760 --> 00:01:25,520
表現と状態の間の因果関係です。

22
00:01:25,680 --> 00:01:27,720
状態を変えると

23
00:01:27,880 --> 00:01:32,520
システムの状態だけでなく
システムの表現も変更されます。

24
00:01:33,000 --> 00:01:37,080
何がうれしいのかと言うと

25
00:01:37,480 --> 00:01:41,160
オブジェクトの中身を見るために

26
00:01:41,320 --> 00:01:43,240
このイントロスペクションと
インターセッションを使うのです。

27
00:01:43,400 --> 00:01:48,800
コレクションを 1 つ定義します。
OrderedCollection です。

28
00:01:49,680 --> 00:01:54,680
そして Pharo のインスペクターという
道具を使って

29
00:01:54,840 --> 00:01:57,960
オブジェクトの内側を見ることができます。

30
00:01:58,120 --> 00:02:02,200
OrderedCollection クラスの
インスタンスオブジェクトが

31
00:02:02,360 --> 00:02:05,840
ここにありますが
中に、インスタンス変数があります。

32
00:02:06,000 --> 00:02:07,720
array と
firstIndex と lastIndex です。

33
00:02:07,880 --> 00:02:10,600
このオブジェクトのインスタンス変数の値は

34
00:02:10,760 --> 00:02:15,400
1 と 12 と
そして 12 要素の配列があります。いいですね？

35
00:02:15,560 --> 00:02:19,400
このインスペクターというツールは

36
00:02:19,560 --> 00:02:22,000
一体どうやってオブジェクトの内側を
みることができるのでしょう？

37
00:02:22,160 --> 00:02:25,120
オブジェクトの内部状態を
どうやって見るのでしょう？

38
00:02:26,600 --> 00:02:31,160
インスペクターはイントロスペクション
メソッドを使ってオブジェクトの内側を見ます。

39
00:02:31,320 --> 00:02:34,360
イントロスペクションメソッドは
Object で沢山定義されています。

40
00:02:34,520 --> 00:02:37,800
instVarAt: でインスタンス変数を

41
00:02:37,960 --> 00:02:40,960
整数インデックスで読むことができます。

42
00:02:41,120 --> 00:02:44,480
これでこのオブジェクトの
インスタンス変数 1 番を見れます。

43
00:02:44,640 --> 00:02:49,600
このオブジェクトのインスタンス変数 1 番に
新しい値を与えて変更することができます。

44
00:02:49,760 --> 00:02:52,160
あるいはインスタンス変数名でアクセスしたり

45
00:02:52,320 --> 00:02:56,000
その値を変えることもできます。
instVarNamed:put: です。いいですね？

46
00:02:58,320 --> 00:03:01,160
ここに例があります。
通常の方法で点を生成して

47
00:03:01,320 --> 00:03:04,880
その点というのは 10@3 ですが

48
00:03:05,040 --> 00:03:07,360
instVarNamed: 'x' として

49
00:03:07,520 --> 00:03:11,760
この点のインスタンス変数 x の値を得ます。

50
00:03:11,920 --> 00:03:14,080
得られる値は 10 です。

51
00:03:14,240 --> 00:03:17,960
そして instVarNamed: 'x' put: 33 で

52
00:03:18,120 --> 00:03:21,840
この点のインスタンス変数 x の値を

53
00:03:22,000 --> 00:03:25,680
10 から 33 に変更します。

54
00:03:25,840 --> 00:03:30,080
イントロスペクションと
インターセッションを使って

55
00:03:30,240 --> 00:03:34,120
オブジェクトの内部状態を見てきました。

56
00:03:34,280 --> 00:03:38,200
instVarNamed:put: はインターセッションです。
いいですね？

57
00:03:38,360 --> 00:03:40,800
ここで重要なことは
カプセル化が破られているということです。

58
00:03:40,960 --> 00:03:45,560
外部のオブジェクトがこのオブジェクトの
内部状態を変更しました。

59
00:03:45,720 --> 00:03:49,600
これはカプセル化に違反しています。
しかし、とても有用です。

60
00:03:49,760 --> 00:03:52,960
ツールを作ったり、それを使って
開発するのに便利です。

61
00:03:53,120 --> 00:03:56,840
アプリケーションの通常のコードで
使うようなものではありませんが

62
00:03:57,000 --> 00:04:00,160
開発ツールを構築する上では
強烈にパワフルなのです。

63
00:04:00,320 --> 00:04:02,320
コードインスペクターが良い例です。

64
00:04:03,680 --> 00:04:07,360
イントロスペクションの別の例を
お見せします。

65
00:04:07,520 --> 00:04:11,240
オブジェクトのクラスを得る class
メソッドです。Object で定義されています。

66
00:04:11,400 --> 00:04:14,760
この文字列にクラスを尋ねると
String クラスが得られます。

67
00:04:14,920 --> 00:04:17,880
この点にクラスを尋ねると
Point クラスが得られます。

68
00:04:18,040 --> 00:04:21,600
Smalltalk class
Class クラスのクラスを尋ねることもできます。

69
00:04:21,760 --> 00:04:23,840
などなど

70
00:04:24,000 --> 00:04:26,560
基本的にオブジェクトに
class メッセージを送ることで

71
00:04:26,720 --> 00:04:30,880
そのクラスを知ることができます。

72
00:04:31,320 --> 00:04:34,040
システムに問い合わせるメソッドは
沢山あります。

73
00:04:34,200 --> 00:04:38,360
ここで、OrderedCollection に
沢山の問い合わせメッセージを送っています。

74
00:04:38,520 --> 00:04:41,200
全てのスーパークラスを得たり

75
00:04:41,360 --> 00:04:45,520
全てのセレクターを得たり

76
00:04:45,680 --> 00:04:50,680
全てのインスタンス変数名を得たり

77
00:04:50,840 --> 00:04:54,120
全てのサブクラスを得たり

78
00:04:54,280 --> 00:04:56,160
そのコードの全ての行を得るなど…

79
00:04:57,320 --> 00:05:00,920
これらの問い合わせメッセージを使って
システムナビゲーションなどの

80
00:05:01,080 --> 00:05:04,840
トップレベルツールが作られています。

81
00:05:05,000 --> 00:05:09,600
システムナビゲーションは
システムをブラウズするためのツールです。

82
00:05:09,760 --> 00:05:14,360
例えば , メソッドを実装している

83
00:05:15,440 --> 00:05:18,880
全てのクラスを見ることができます。

84
00:05:19,040 --> 00:05:21,720
こんな風にウィンドウが開いて

85
00:05:21,880 --> 00:05:24,600
, の全てのインプリメンターが得られます。

86
00:05:24,760 --> 00:05:29,200
AbstractFileReference クラスが
, メソッドを実装しています。

87
00:05:29,360 --> 00:05:32,280
このメソッドを実装している
全てのクラスのリストが得られます。

88
00:05:33,880 --> 00:05:37,520
もう 1 つ例があります。

89
00:05:38,280 --> 00:05:41,240
メニューやボタンを

90
00:05:41,400 --> 00:05:45,520
クリックすると、背後にあるオブジェクトに
メッセージが送られるようにしたいとします。

91
00:05:45,680 --> 00:05:48,680
メッセージ名はボタンの名前を使います。
ここで

92
00:05:48,840 --> 00:05:53,760
文字列をオブジェクトに送るメッセージに
変換するにはどうしたらいいでしょう？

93
00:05:54,560 --> 00:05:59,480
そのためのインターセッションメソッド
があります。Object の perform: です。

94
00:05:59,640 --> 00:06:03,320
引数としてシンボルを渡して
送りたいメッセージの名前とします。

95
00:06:03,480 --> 00:06:06,360
するとこのオブジェクトに
このメッセージが送られます。

96
00:06:06,520 --> 00:06:10,560
同種のメッセージに
perform:with: があります。

97
00:06:10,720 --> 00:06:14,960
実行するメソッド名をシンボルとして与えて

98
00:06:15,120 --> 00:06:16,800
引数を渡します。

99
00:06:16,960 --> 00:06:19,400
例えば 古典的なメッセージ送信での
5 factorial を

100
00:06:19,560 --> 00:06:23,280
リフレクションメッセージで行うためには

101
00:06:23,440 --> 00:06:28,960
5 perform: #factorial とします。
オブジェクト 5 に

102
00:06:29,280 --> 00:06:34,680
#factorial メッセージを実行してください
とお願いをしています。

103
00:06:34,880 --> 00:06:39,600
通常のメソッド探索が行われて実行されます。
つまりこれら 2 つは同じです。

104
00:06:40,240 --> 00:06:41,920
もう 1 つ例があります。

105
00:06:42,120 --> 00:06:44,480
コードインスペクタで

106
00:06:44,640 --> 00:06:49,600
OrderedCollection クラスの内側を
見ることができます。

107
00:06:49,760 --> 00:06:54,480
このクラスには属性があります。

108
00:06:54,640 --> 00:06:57,000
例えば、
インスタンス変数 methodDict があります。

109
00:06:57,160 --> 00:07:01,680
OrderedCollection の methodDict は 

110
00:07:01,840 --> 00:07:05,960
Behaviour からきています。
この methodDict には

111
00:07:06,120 --> 00:07:10,360
MethodDictionary のインスタンスがきて
CompiledMethod を持っています。

112
00:07:10,520 --> 00:07:14,360
そういうわけで、このメソッド辞書に

113
00:07:14,520 --> 00:07:17,360
このコンパイル済みメソッドがあって
別のコンパイル済みメソッドもあり

114
00:07:17,520 --> 00:07:20,360
沢山のコンパイル済みメソッドが
あることがわかります。

115
00:07:20,840 --> 00:07:25,480
これらのコンパイル済みメソッドに
ソースコードを尋ねることができます。

116
00:07:25,920 --> 00:07:28,280
self getSource とすると

117
00:07:28,440 --> 00:07:30,600
そのコンパイル済みメソッドの
ソースコードが得られます。

118
00:07:30,880 --> 00:07:32,200
更に

119
00:07:32,400 --> 00:07:35,800
コンパイル済みメソッドを
直接実行することもできます。

120
00:07:35,960 --> 00:07:39,200
valueWithReceiver:arguments:
メッセージを使います。

121
00:07:39,360 --> 00:07:42,200
ただし、注意してください。
この方法はメソッド探索は行われません。

122
00:07:42,360 --> 00:07:45,920
コンパイル済みメソッドがあれば

123
00:07:46,080 --> 00:07:48,600
メッセージを介さずに直接実行できるのです。

124
00:07:48,760 --> 00:07:53,520
ここで、Integer クラスから

125
00:07:53,680 --> 00:07:56,240
コンパイル済みメソッド factorial
を得て

126
00:07:56,400 --> 00:07:59,320
それにメッセージを送ります。
valueWithReceiver:arguments:

127
00:07:59,480 --> 00:08:03,200
引数として、レシーバーに 5 を指定して

128
00:08:03,360 --> 00:08:06,320
引数は空です。単項メッセージなので。

129
00:08:06,480 --> 00:08:08,800
すると結果が得られます。

130
00:08:09,760 --> 00:08:14,880
メソッド探索なしにコンパイル済み
メソッドを実行しました。

131
00:08:15,240 --> 00:08:18,360
まとめると
リフレクションは極めて強力です。

132
00:08:18,560 --> 00:08:22,360
イントロスペクションで

133
00:08:22,840 --> 00:08:25,240
システム全体を見てみました。
システムがそれ自身の中で

134
00:08:25,400 --> 00:08:26,880
オブジェクトとして表現されます。

135
00:08:27,040 --> 00:08:29,440
そしてシステムの状態を変更
することもできます。

136
00:08:29,600 --> 00:08:33,240
これを使って全てのオブジェクトに
汎用的な方法でツールを構築できます。

137
00:08:33,960 --> 00:08:36,400
全てのオブジェクトに共通する
構造を持つプロトコルで

138
00:08:36,560 --> 00:08:40,000
オブジェクトと対話することができます。

139
00:08:40,160 --> 00:08:43,800
ただし、カプセル化に違反していることに
注意してください。

140
00:08:43,960 --> 00:08:48,080
アプリケーションコードに使うものではなく
ツール作りに使うためのものです。

141
00:08:48,240 --> 00:08:52,840
コードインスペクターは
リフレクションを使って作られています。

142
00:08:53,000 --> 00:08:56,560
また、Pharo でリフレクションが
どう実現されているか見ることができます。
