WEBVTT

00:00:00.400 --> 00:00:03.560 align:middle
こんにちは。この講義では
リフレクションを見ていきます。

00:00:03.720 --> 00:00:08.640 align:middle
Pharo 自身の中を見て
リフレクションの利用法を見ていきましょう。

00:00:09.600 --> 00:00:11.880 align:middle
リフレクションは

00:00:12.040 --> 00:00:15.960 align:middle
大きく 2 つに分類できます。

00:00:16.120 --> 00:00:18.000 align:middle
イントロスペクションは

00:00:18.160 --> 00:00:21.240 align:middle
プログラムが自身の状態を観察する
能力のことです。

00:00:21.400 --> 00:00:25.880 align:middle
インターセッションはプログラムが
自分自身を修正する能力です。

00:00:26.040 --> 00:00:29.040 align:middle
レイフィケーションは

00:00:30.640 --> 00:00:34.560 align:middle
自身の状態や実行を変更するために

00:00:34.720 --> 00:00:39.760 align:middle
通常は暗黙になっているものを
明示化する概念です。

00:00:39.920 --> 00:00:43.920 align:middle
例えば、Pharo では

00:00:44.080 --> 00:00:49.400 align:middle
実行スタックは明示的です。
古典的なオブジェクトとして表現されます。

00:00:49.920 --> 00:00:55.280 align:middle
Pharo ではクラスも
完全に古典的なオブジェクトです。

00:00:55.480 --> 00:00:58.960 align:middle
他の言語には
クラスはオブジェクトではないものもあります。

00:01:00.040 --> 00:01:02.160 align:middle
リフレクションのあるシステムでは

00:01:02.320 --> 00:01:06.600 align:middle
それ自身の表現を得ることができます。

00:01:06.760 --> 00:01:09.600 align:middle
それ自身を表現することができ

00:01:09.760 --> 00:01:14.840 align:middle
その表現を使ってそれ自身を変更できます。

00:01:15.000 --> 00:01:19.600 align:middle
表現を変更した時
そのシステムの状態を変更します。

00:01:19.760 --> 00:01:22.600 align:middle
それを因果関係と呼びます。

00:01:22.760 --> 00:01:25.520 align:middle
表現と状態の間の因果関係です。

00:01:25.680 --> 00:01:27.720 align:middle
状態を変えると

00:01:27.880 --> 00:01:32.520 align:middle
システムの状態だけでなく
システムの表現も変更されます。

00:01:33.000 --> 00:01:37.080 align:middle
何がうれしいのかと言うと

00:01:37.480 --> 00:01:41.160 align:middle
オブジェクトの中身を見るために

00:01:41.320 --> 00:01:43.240 align:middle
このイントロスペクションと
インターセッションを使うのです。

00:01:43.400 --> 00:01:48.800 align:middle
コレクションを 1 つ定義します。
OrderedCollection です。

00:01:49.680 --> 00:01:54.680 align:middle
そして Pharo のインスペクターという
道具を使って

00:01:54.840 --> 00:01:57.960 align:middle
オブジェクトの内側を見ることができます。

00:01:58.120 --> 00:02:02.200 align:middle
OrderedCollection クラスの
インスタンスオブジェクトが

00:02:02.360 --> 00:02:05.840 align:middle
ここにありますが
中に、インスタンス変数があります。

00:02:06.000 --> 00:02:07.720 align:middle
array と
firstIndex と lastIndex です。

00:02:07.880 --> 00:02:10.600 align:middle
このオブジェクトのインスタンス変数の値は

00:02:10.760 --> 00:02:15.400 align:middle
1 と 12 と
そして 12 要素の配列があります。いいですね？

00:02:15.560 --> 00:02:19.400 align:middle
このインスペクターというツールは

00:02:19.560 --> 00:02:22.000 align:middle
一体どうやってオブジェクトの内側を
みることができるのでしょう？

00:02:22.160 --> 00:02:25.120 align:middle
オブジェクトの内部状態を
どうやって見るのでしょう？

00:02:26.600 --> 00:02:31.160 align:middle
インスペクターはイントロスペクション
メソッドを使ってオブジェクトの内側を見ます。

00:02:31.320 --> 00:02:34.360 align:middle
イントロスペクションメソッドは
Object で沢山定義されています。

00:02:34.520 --> 00:02:37.800 align:middle
instVarAt: でインスタンス変数を

00:02:37.960 --> 00:02:40.960 align:middle
整数インデックスで読むことができます。

00:02:41.120 --> 00:02:44.480 align:middle
これでこのオブジェクトの
インスタンス変数 1 番を見れます。

00:02:44.640 --> 00:02:49.600 align:middle
このオブジェクトのインスタンス変数 1 番に
新しい値を与えて変更することができます。

00:02:49.760 --> 00:02:52.160 align:middle
あるいはインスタンス変数名でアクセスしたり

00:02:52.320 --> 00:02:56.000 align:middle
その値を変えることもできます。
instVarNamed:put: です。いいですね？

00:02:58.320 --> 00:03:01.160 align:middle
ここに例があります。
通常の方法で点を生成して

00:03:01.320 --> 00:03:04.880 align:middle
その点というのは 10@3 ですが

00:03:05.040 --> 00:03:07.360 align:middle
instVarNamed: 'x' として

00:03:07.520 --> 00:03:11.760 align:middle
この点のインスタンス変数 x の値を得ます。

00:03:11.920 --> 00:03:14.080 align:middle
得られる値は 10 です。

00:03:14.240 --> 00:03:17.960 align:middle
そして instVarNamed: 'x' put: 33 で

00:03:18.120 --> 00:03:21.840 align:middle
この点のインスタンス変数 x の値を

00:03:22.000 --> 00:03:25.680 align:middle
10 から 33 に変更します。

00:03:25.840 --> 00:03:30.080 align:middle
イントロスペクションと
インターセッションを使って

00:03:30.240 --> 00:03:34.120 align:middle
オブジェクトの内部状態を見てきました。

00:03:34.280 --> 00:03:38.200 align:middle
instVarNamed:put: はインターセッションです。
いいですね？

00:03:38.360 --> 00:03:40.800 align:middle
ここで重要なことは
カプセル化が破られているということです。

00:03:40.960 --> 00:03:45.560 align:middle
外部のオブジェクトがこのオブジェクトの
内部状態を変更しました。

00:03:45.720 --> 00:03:49.600 align:middle
これはカプセル化に違反しています。
しかし、とても有用です。

00:03:49.760 --> 00:03:52.960 align:middle
ツールを作ったり、それを使って
開発するのに便利です。

00:03:53.120 --> 00:03:56.840 align:middle
アプリケーションの通常のコードで
使うようなものではありませんが

00:03:57.000 --> 00:04:00.160 align:middle
開発ツールを構築する上では
強烈にパワフルなのです。

00:04:00.320 --> 00:04:02.320 align:middle
コードインスペクターが良い例です。

00:04:03.680 --> 00:04:07.360 align:middle
イントロスペクションの別の例を
お見せします。

00:04:07.520 --> 00:04:11.240 align:middle
オブジェクトのクラスを得る class
メソッドです。Object で定義されています。

00:04:11.400 --> 00:04:14.760 align:middle
この文字列にクラスを尋ねると
String クラスが得られます。

00:04:14.920 --> 00:04:17.880 align:middle
この点にクラスを尋ねると
Point クラスが得られます。

00:04:18.040 --> 00:04:21.600 align:middle
Smalltalk class
Class クラスのクラスを尋ねることもできます。

00:04:21.760 --> 00:04:23.840 align:middle
などなど

00:04:24.000 --> 00:04:26.560 align:middle
基本的にオブジェクトに
class メッセージを送ることで

00:04:26.720 --> 00:04:30.880 align:middle
そのクラスを知ることができます。

00:04:31.320 --> 00:04:34.040 align:middle
システムに問い合わせるメソッドは
沢山あります。

00:04:34.200 --> 00:04:38.360 align:middle
ここで、OrderedCollection に
沢山の問い合わせメッセージを送っています。

00:04:38.520 --> 00:04:41.200 align:middle
全てのスーパークラスを得たり

00:04:41.360 --> 00:04:45.520 align:middle
全てのセレクターを得たり

00:04:45.680 --> 00:04:50.680 align:middle
全てのインスタンス変数名を得たり

00:04:50.840 --> 00:04:54.120 align:middle
全てのサブクラスを得たり

00:04:54.280 --> 00:04:56.160 align:middle
そのコードの全ての行を得るなど…

00:04:57.320 --> 00:05:00.920 align:middle
これらの問い合わせメッセージを使って
システムナビゲーションなどの

00:05:01.080 --> 00:05:04.840 align:middle
トップレベルツールが作られています。

00:05:05.000 --> 00:05:09.600 align:middle
システムナビゲーションは
システムをブラウズするためのツールです。

00:05:09.760 --> 00:05:14.360 align:middle
例えば , メソッドを実装している

00:05:15.440 --> 00:05:18.880 align:middle
全てのクラスを見ることができます。

00:05:19.040 --> 00:05:21.720 align:middle
こんな風にウィンドウが開いて

00:05:21.880 --> 00:05:24.600 align:middle
, の全てのインプリメンターが得られます。

00:05:24.760 --> 00:05:29.200 align:middle
AbstractFileReference クラスが
, メソッドを実装しています。

00:05:29.360 --> 00:05:32.280 align:middle
このメソッドを実装している
全てのクラスのリストが得られます。

00:05:33.880 --> 00:05:37.520 align:middle
もう 1 つ例があります。

00:05:38.280 --> 00:05:41.240 align:middle
メニューやボタンを

00:05:41.400 --> 00:05:45.520 align:middle
クリックすると、背後にあるオブジェクトに
メッセージが送られるようにしたいとします。

00:05:45.680 --> 00:05:48.680 align:middle
メッセージ名はボタンの名前を使います。
ここで

00:05:48.840 --> 00:05:53.760 align:middle
文字列をオブジェクトに送るメッセージに
変換するにはどうしたらいいでしょう？

00:05:54.560 --> 00:05:59.480 align:middle
そのためのインターセッションメソッド
があります。Object の perform: です。

00:05:59.640 --> 00:06:03.320 align:middle
引数としてシンボルを渡して
送りたいメッセージの名前とします。

00:06:03.480 --> 00:06:06.360 align:middle
するとこのオブジェクトに
このメッセージが送られます。

00:06:06.520 --> 00:06:10.560 align:middle
同種のメッセージに
perform:with: があります。

00:06:10.720 --> 00:06:14.960 align:middle
実行するメソッド名をシンボルとして与えて

00:06:15.120 --> 00:06:16.800 align:middle
引数を渡します。

00:06:16.960 --> 00:06:19.400 align:middle
例えば 古典的なメッセージ送信での
5 factorial を

00:06:19.560 --> 00:06:23.280 align:middle
リフレクションメッセージで行うためには

00:06:23.440 --> 00:06:28.960 align:middle
5 perform: #factorial とします。
オブジェクト 5 に

00:06:29.280 --> 00:06:34.680 align:middle
#factorial メッセージを実行してください
とお願いをしています。

00:06:34.880 --> 00:06:39.600 align:middle
通常のメソッド探索が行われて実行されます。
つまりこれら 2 つは同じです。

00:06:40.240 --> 00:06:41.920 align:middle
もう 1 つ例があります。

00:06:42.120 --> 00:06:44.480 align:middle
コードインスペクタで

00:06:44.640 --> 00:06:49.600 align:middle
OrderedCollection クラスの内側を
見ることができます。

00:06:49.760 --> 00:06:54.480 align:middle
このクラスには属性があります。

00:06:54.640 --> 00:06:57.000 align:middle
例えば、
インスタンス変数 methodDict があります。

00:06:57.160 --> 00:07:01.680 align:middle
OrderedCollection の methodDict は 

00:07:01.840 --> 00:07:05.960 align:middle
Behaviour からきています。
この methodDict には

00:07:06.120 --> 00:07:10.360 align:middle
MethodDictionary のインスタンスがきて
CompiledMethod を持っています。

00:07:10.520 --> 00:07:14.360 align:middle
そういうわけで、このメソッド辞書に

00:07:14.520 --> 00:07:17.360 align:middle
このコンパイル済みメソッドがあって
別のコンパイル済みメソッドもあり

00:07:17.520 --> 00:07:20.360 align:middle
沢山のコンパイル済みメソッドが
あることがわかります。

00:07:20.840 --> 00:07:25.480 align:middle
これらのコンパイル済みメソッドに
ソースコードを尋ねることができます。

00:07:25.920 --> 00:07:28.280 align:middle
self getSource とすると

00:07:28.440 --> 00:07:30.600 align:middle
そのコンパイル済みメソッドの
ソースコードが得られます。

00:07:30.880 --> 00:07:32.200 align:middle
更に

00:07:32.400 --> 00:07:35.800 align:middle
コンパイル済みメソッドを
直接実行することもできます。

00:07:35.960 --> 00:07:39.200 align:middle
valueWithReceiver:arguments:
メッセージを使います。

00:07:39.360 --> 00:07:42.200 align:middle
ただし、注意してください。
この方法はメソッド探索は行われません。

00:07:42.360 --> 00:07:45.920 align:middle
コンパイル済みメソッドがあれば

00:07:46.080 --> 00:07:48.600 align:middle
メッセージを介さずに直接実行できるのです。

00:07:48.760 --> 00:07:53.520 align:middle
ここで、Integer クラスから

00:07:53.680 --> 00:07:56.240 align:middle
コンパイル済みメソッド factorial
を得て

00:07:56.400 --> 00:07:59.320 align:middle
それにメッセージを送ります。
valueWithReceiver:arguments:

00:07:59.480 --> 00:08:03.200 align:middle
引数として、レシーバーに 5 を指定して

00:08:03.360 --> 00:08:06.320 align:middle
引数は空です。単項メッセージなので。

00:08:06.480 --> 00:08:08.800 align:middle
すると結果が得られます。

00:08:09.760 --> 00:08:14.880 align:middle
メソッド探索なしにコンパイル済み
メソッドを実行しました。

00:08:15.240 --> 00:08:18.360 align:middle
まとめると
リフレクションは極めて強力です。

00:08:18.560 --> 00:08:22.360 align:middle
イントロスペクションで

00:08:22.840 --> 00:08:25.240 align:middle
システム全体を見てみました。
システムがそれ自身の中で

00:08:25.400 --> 00:08:26.880 align:middle
オブジェクトとして表現されます。

00:08:27.040 --> 00:08:29.440 align:middle
そしてシステムの状態を変更
することもできます。

00:08:29.600 --> 00:08:33.240 align:middle
これを使って全てのオブジェクトに
汎用的な方法でツールを構築できます。

00:08:33.960 --> 00:08:36.400 align:middle
全てのオブジェクトに共通する
構造を持つプロトコルで

00:08:36.560 --> 00:08:40.000 align:middle
オブジェクトと対話することができます。

00:08:40.160 --> 00:08:43.800 align:middle
ただし、カプセル化に違反していることに
注意してください。

00:08:43.960 --> 00:08:48.080 align:middle
アプリケーションコードに使うものではなく
ツール作りに使うためのものです。

00:08:48.240 --> 00:08:52.840 align:middle
コードインスペクターは
リフレクションを使って作られています。

00:08:53.000 --> 00:08:56.560 align:middle
また、Pharo でリフレクションが
どう実現されているか見ることができます。

