WEBVTT

00:00:00.480 --> 00:00:04.600 align:middle
このビデオでは Pharo の先進的な
側面に注目します。

00:00:04.800 --> 00:00:10.800 align:middle
ライブプログラミングに必要な
リフレクティブな操作です。

00:00:11.680 --> 00:00:16.680 align:middle
クラスを再コンパイルする時に
何が起きるのかを見ていきましょう。

00:00:17.040 --> 00:00:20.080 align:middle
そしてライブプログラミングを
実践するために

00:00:20.200 --> 00:00:24.720 align:middle
必要なリフレクティブな操作を
説明します。

00:00:24.920 --> 00:00:26.560 align:middle
ここに典型例があります。

00:00:26.720 --> 00:00:30.320 align:middle
我々は通常はまずクラスを定義して

00:00:30.600 --> 00:00:34.640 align:middle
それからメソッドを追加して
そのクラスのインスタンスを作ります。

00:00:35.160 --> 00:00:40.400 align:middle
そしてクラスを再定義して
新しいインスタンス変数を追加します。

00:00:41.200 --> 00:00:45.640 align:middle
では、属性が 1 つ減ったら

00:00:46.160 --> 00:00:48.440 align:middle
既に存在しているインスタンスは
どうなるのでしょう？

00:00:48.680 --> 00:00:53.920 align:middle
元のインスタンスを新しいクラスに
マイグレーションする

00:00:54.280 --> 00:00:57.360 align:middle
メカニズムが必要です。

00:00:57.640 --> 00:00:59.160 align:middle
それで動き続けます。

00:00:59.600 --> 00:01:03.200 align:middle
クラスの動的な再定義や
メソッドの再コンパイルを可能にして

00:01:04.440 --> 00:01:09.160 align:middle
インスタンスを新しいバージョンのクラスに

00:01:09.600 --> 00:01:11.040 align:middle
自動的かつ透過的に

00:01:11.400 --> 00:01:15.160 align:middle
マイグレーションさせるための

00:01:15.360 --> 00:01:18.200 align:middle
操作を見ていきます。

00:01:18.520 --> 00:01:22.560 align:middle
そのためにはまず、特定のクラスの
全てのインスタンスを得る必要があります。

00:01:22.840 --> 00:01:28.280 align:middle
それから、それらのオブジェクトを
指していたポインタを

00:01:28.840 --> 00:01:31.920 align:middle
新しいオブジェクトを指すように
全て置き換えていきます。

00:01:32.400 --> 00:01:33.400 align:middle
いいですか？

00:01:34.160 --> 00:01:38.920 align:middle
まずは、あるクラスの全てのインスタンスを
どうやって集めてくるかです。

00:01:39.400 --> 00:01:43.560 align:middle
クラスに
allInstances メッセージを送ると

00:01:43.800 --> 00:01:47.320 align:middle
その全てのインスタンスが得られます。

00:01:47.640 --> 00:01:51.440 align:middle
通常のオブジェクトのコレクションです。

00:01:51.640 --> 00:01:57.800 align:middle
Window クラスに送れば
Window オブジェクトのコレクションが得られます。

00:01:58.280 --> 00:02:02.760 align:middle
最初の要素を取り出して
close メッセージを送ることができます。

00:02:02.920 --> 00:02:06.840 align:middle
close メソッドは Window クラスで
定義されているので。

00:02:07.360 --> 00:02:11.840 align:middle
リフレクティブなプリミティブには
pointersTo もあります。

00:02:12.160 --> 00:02:16.920 align:middle
このメッセージをオブジェクトに送ると
そのオブジェクトへの参照を持つ

00:02:17.400 --> 00:02:21.000 align:middle
全てのオブジェクトのコレクションを
得ることができます。

00:02:21.200 --> 00:02:23.040 align:middle
オブジェクトを入れ替えたい時には

00:02:23.200 --> 00:02:27.320 align:middle
とても便利です。

00:02:29.560 --> 00:02:34.080 align:middle
ポインタを入れ替えるプリミティブは
become: です。

00:02:34.600 --> 00:02:39.760 align:middle
2 つのオブジェクトを
入れ替えることができます。

00:02:41.160 --> 00:02:43.840 align:middle
2 つのオブジェクトを対称的に入れ替えます。

00:02:44.200 --> 00:02:48.200 align:middle
システム中のこのオブジェクトを指す全て

00:02:48.720 --> 00:02:51.160 align:middle
この場合は ポインタが 2 つですが

00:02:51.360 --> 00:02:55.840 align:middle
それらは、このオブジェクトを指すように
置き換えられます。

00:02:57.280 --> 00:03:01.720 align:middle
こちら側のポインタは全て破棄されて

00:03:02.280 --> 00:03:04.080 align:middle
オブジェクトが入れ替えられます。

00:03:06.360 --> 00:03:11.680 align:middle
become: はシステム中のポインタを
対称的に入れ替えるということです。

00:03:13.280 --> 00:03:15.080 align:middle
ここに例題があります。

00:03:15.320 --> 00:03:17.600 align:middle
pt1 は

00:03:17.800 --> 00:03:22.320 align:middle
点オブジェクト 0@0 を指して
変数 pt2 も

00:03:22.840 --> 00:03:25.320 align:middle
その 0@0 オブジェクトを指します。

00:03:25.560 --> 00:03:29.560 align:middle
さらに、変数 pt3 は
点 100@100 を指します。

00:03:29.800 --> 00:03:33.200 align:middle
そして、pt1 become: pt3 と書きます。

00:03:34.160 --> 00:03:38.680 align:middle
変数 pt1 として示されるこのオブジェクト
を指していたものは

00:03:38.920 --> 00:03:41.440 align:middle
pt3 を指すようになりました。

00:03:42.200 --> 00:03:44.400 align:middle
つまり、pt1 への全てのポインタが
pt3 を指しています。

00:03:44.600 --> 00:03:49.760 align:middle
変数 pt2 は pt1 と同じオブジェクトを
指していましたが

00:03:49.920 --> 00:03:54.400 align:middle
pt3 で参照されていたオブジェクトを
指しています。

00:03:54.760 --> 00:04:00.440 align:middle
pt3 については、対称的なので
pt1 が指していたオブジェクトを指します。

00:04:00.640 --> 00:04:01.760 align:middle
一番上のものです。

00:04:02.800 --> 00:04:06.080 align:middle
そして pt1 は pt3 だったものを
指しています。

00:04:06.280 --> 00:04:10.000 align:middle
つまり、ポインタが
対称的に入れ替わりました。

00:04:11.200 --> 00:04:14.800 align:middle
非対称な入れ替えは
becomeForward: です。

00:04:15.440 --> 00:04:18.400 align:middle
ポインタの入れ替えをするのですが

00:04:18.640 --> 00:04:23.360 align:middle
このオブジェクトを指していたものは
こちらのオブジェクトに置き換わり

00:04:24.080 --> 00:04:28.400 align:middle
逆には働きません。
このオブジェクトへのポインタはそのままです。

00:04:31.520 --> 00:04:34.640 align:middle
別の例があります。

00:04:35.280 --> 00:04:39.640 align:middle
becomeForward: を実行すると

00:04:39.920 --> 00:04:45.080 align:middle
pt1 と pt2 に影響が出ます。

00:04:45.600 --> 00:04:48.640 align:middle
pt3 は becomeForard: の
影響を受けません。

00:04:48.840 --> 00:04:53.000 align:middle
このオブジェクトを指していたものは
変化しません。

00:04:55.400 --> 00:04:59.840 align:middle
また別のリフレクティブなプリミティブに
adoptInstance: があります。

00:05:00.200 --> 00:05:02.640 align:middle
これはオブジェクトのクラスを入れ替えます。

00:05:02.840 --> 00:05:07.920 align:middle
引数として渡されたインスタンスを
クラスに「引き取る」ように頼みます。

00:05:08.560 --> 00:05:13.400 align:middle
クラスを変更することはとても強力な
道具ですが、制限もあります。

00:05:13.640 --> 00:05:17.520 align:middle
そのオブジェクト

00:05:18.160 --> 00:05:19.840 align:middle
この場合 anInstance ですが
このオブジェクトの元のクラスが

00:05:20.040 --> 00:05:24.680 align:middle
新しいクラスのフォーマットと
互換性があることが必須条件です。

00:05:25.440 --> 00:05:29.160 align:middle
どんなオブジェクトも入れ替える
というわけにはいきません。

00:05:29.360 --> 00:05:31.840 align:middle
インデックス付き、などなど

00:05:32.080 --> 00:05:36.000 align:middle
オブジェクトのフォーマットは
とても重要です。

00:05:36.680 --> 00:05:40.640 align:middle
クラスとは何かというと

00:05:40.920 --> 00:05:43.360 align:middle
クラスは本質的にはフォーマットです。

00:05:43.640 --> 00:05:47.200 align:middle
フォーマットがインスタンス変数の数や

00:05:47.400 --> 00:05:52.520 align:middle
可変領域の型を規定します。
前の講義で説明しましたね。

00:05:52.840 --> 00:05:56.000 align:middle
クラスはスーパークラスや
メソッド辞書を持っています。

00:05:56.840 --> 00:06:01.680 align:middle
Behavior クラスがあります。
これは Class クラスのスーパークラスで

00:06:02.080 --> 00:06:07.520 align:middle
クラスの基本的な振る舞いを定義しています。

00:06:08.160 --> 00:06:11.000 align:middle
クラスの最小限の基本機能です。

00:06:11.200 --> 00:06:14.720 align:middle
クラスはスーパークラスと
メソッド辞書と

00:06:14.840 --> 00:06:18.200 align:middle
フォーマットを持っています。

00:06:19.200 --> 00:06:24.440 align:middle
ここまで話してきた
リフレクティブな振る舞いの機能を

00:06:25.000 --> 00:06:27.360 align:middle
具体的な例を挙げながら

00:06:28.440 --> 00:06:33.440 align:middle
まとめてみましょう。

00:06:34.760 --> 00:06:37.800 align:middle
それに沿ってコードを説明していきます。

00:06:38.000 --> 00:06:42.400 align:middle
これらの 3 行で
Behavior クラスのインスタンスを作ります。

00:06:42.640 --> 00:06:44.280 align:middle
いいですか、クラスですよ。

00:06:44.640 --> 00:06:50.080 align:middle
Behavior という名前のクラスの
インスタンスを作ります。

00:06:51.600 --> 00:06:54.400 align:middle
これを behavior と呼ぶことにします。

00:06:55.040 --> 00:07:00.600 align:middle
このオブジェクトは Model クラスを
継承するように記述します。

00:07:02.000 --> 00:07:03.000 align:middle
こんな風に。

00:07:03.680 --> 00:07:08.080 align:middle
この behavior オブジェクトの
フォーマットを設定します。

00:07:08.600 --> 00:07:12.400 align:middle
そして Model クラスのインスタンスを
生成します。

00:07:14.520 --> 00:07:16.360 align:middle
このオブジェクトを model とします。

00:07:17.200 --> 00:07:20.080 align:middle
ここ、このコードのこの行が重要です。

00:07:20.760 --> 00:07:23.920 align:middle
model オブジェクトのクラスを

00:07:24.080 --> 00:07:28.920 align:middle
引数として渡したクラス
つまり behavior に変更します。

00:07:29.200 --> 00:07:34.400 align:middle
それまでのインスタンス関係のリンクを切って
このクラスのインスタンスにします。

00:07:34.800 --> 00:07:37.400 align:middle
このクラスは
Model クラスのサブクラスです。

00:07:38.800 --> 00:07:43.400 align:middle
さて、ここでこのクラスの
新しいメソッドをコンパイルします。

00:07:43.600 --> 00:07:47.400 align:middle
メソッド foo は 2 を返します。
これをコンパイルします。

00:07:48.840 --> 00:07:51.840 align:middle
behavior オブジェクトで。

00:07:53.560 --> 00:07:55.280 align:middle
見ての通り

00:07:55.560 --> 00:07:59.840 align:middle
ここの model オブジェクトに
foo メッセージを

00:08:01.000 --> 00:08:02.160 align:middle
こんな風に送ると

00:08:02.760 --> 00:08:04.160 align:middle
2 が返ってきます。

00:08:04.640 --> 00:08:06.720 align:middle
この部分はメソッド探索についてです。

00:08:07.400 --> 00:08:09.040 align:middle
foo メッセージを送ります。

00:08:09.200 --> 00:08:14.600 align:middle
model オブジェクトはそのクラスつまり
behavior オブジェクトで探索します。

00:08:14.800 --> 00:08:17.360 align:middle
そしてメソッドが見つかります。

00:08:17.760 --> 00:08:19.160 align:middle
完璧に動作します。

00:08:19.920 --> 00:08:24.080 align:middle
しかし Model クラスのインスタンスを

00:08:25.200 --> 00:08:26.200 align:middle
このようにして作って

00:08:26.560 --> 00:08:28.360 align:middle
foo メッセージを送っても

00:08:29.360 --> 00:08:33.360 align:middle
MessageNotUnderstood エラーが
発生します。

00:08:33.640 --> 00:08:35.800 align:middle
メソッド探索が

00:08:36.080 --> 00:08:39.080 align:middle
そのオブジェクトのクラス
つまり Model クラスから探すからです。

00:08:39.320 --> 00:08:43.920 align:middle
foo メソッドは Model クラスや
スーパークラスのメソッド辞書では見つかりません。

00:08:45.040 --> 00:08:51.040 align:middle
この高度なメカニズムを使うと
Model クラスの特定のインスタンスにだけ

00:08:51.520 --> 00:08:54.040 align:middle
振る舞いを与えることができます。

00:08:54.200 --> 00:08:57.840 align:middle
わかりやすくするために、このやり方を
Set クラスにも適用してみましょう。

00:08:58.040 --> 00:09:01.280 align:middle
Set クラスのインスタンス set1 を
生成します。

00:09:01.800 --> 00:09:05.720 align:middle
Set クラスのメソッド辞書には
add: メソッドがあります。

00:09:06.400 --> 00:09:11.520 align:middle
Set クラスの特定のインスタンスにだけ
add: メソッドを変更したいとします。

00:09:11.720 --> 00:09:15.360 align:middle
特定のインスタンスに
特定の振る舞いということです。

00:09:15.520 --> 00:09:18.400 align:middle
そこで匿名のクラスを作ります。

00:09:18.840 --> 00:09:22.920 align:middle
Set クラスを継承します。

00:09:23.280 --> 00:09:25.200 align:middle
ここにその継承関係があります。

00:09:25.600 --> 00:09:31.160 align:middle
set2 オブジェクトは
この匿名クラスのインスタンスです。

00:09:31.720 --> 00:09:37.000 align:middle
その匿名クラスのメソッド辞書で
add: メソッドを

00:09:37.320 --> 00:09:40.640 align:middle
set2 に特定の振る舞いで再定義します。

00:09:40.920 --> 00:09:45.800 align:middle
ここで add: メッセージを
set2 オブジェクトに送ります。

00:09:46.080 --> 00:09:48.400 align:middle
すると本来とは異なる別の振る舞いをします。

00:09:48.800 --> 00:09:52.320 align:middle
この set1 にメッセージを送っていたら

00:09:53.600 --> 00:09:58.040 align:middle
このメソッドが選択されていたでしょうが
それとは異なる振る舞いをします。

00:09:58.280 --> 00:10:03.360 align:middle
つまり、これら 2 つの集合は
add: メッセージに別々の反応をします。

00:10:03.680 --> 00:10:07.080 align:middle
ここに演習問題となるコードがあります。

00:10:07.400 --> 00:10:11.280 align:middle
さきほどと同様に
Behavior クラスのインスタンスとして

00:10:11.640 --> 00:10:13.800 align:middle
クラスを作ります。

00:10:14.080 --> 00:10:16.840 align:middle
スーパークラスを Set クラスとします。

00:10:17.400 --> 00:10:18.640 align:middle
フォーマットを設定します。

00:10:18.840 --> 00:10:23.600 align:middle
この匿名クラスで
add: メソッドをコンパイルします。

00:10:24.080 --> 00:10:29.360 align:middle
これで Set クラスで定義されている
add: メソッドを再定義します。

00:10:30.080 --> 00:10:36.080 align:middle
Transcript show を使って
add: メソッドの実行を表示します。

00:10:36.400 --> 00:10:40.680 align:middle
それから super を使って
Set クラスでの add: メソッドを実行します。

00:10:41.360 --> 00:10:45.720 align:middle
では、1 つ目の集合を作って
テストしてみましょう。

00:10:45.920 --> 00:10:48.600 align:middle
Set クラスはここにあります。

00:10:50.280 --> 00:10:54.280 align:middle
このクラスの最初のインスタンスを生成して
set とします。

00:10:55.080 --> 00:10:57.040 align:middle
そのオブジェクトに
add: メッセージを送ります。

00:10:58.920 --> 00:11:03.760 align:middle
Set クラスの add: メソッドが
使われます。

00:11:05.240 --> 00:11:08.720 align:middle
ここで set のクラスを尋ねると
Set が得られます。

00:11:09.400 --> 00:11:13.160 align:middle
しかし、ここでこのプリミティブを
実行します。

00:11:13.600 --> 00:11:16.200 align:middle
set オブジェクトのクラスを変更して

00:11:16.400 --> 00:11:21.160 align:middle
前の方で Behavior クラスを使って

00:11:22.080 --> 00:11:23.760 align:middle
Set クラスのサブクラスにします。

00:11:24.360 --> 00:11:28.400 align:middle
これでクラスが変更されて
add: メソッドの新しいバージョンを持った

00:11:28.680 --> 00:11:32.000 align:middle
logClass のインスタンスになります。

00:11:32.280 --> 00:11:37.920 align:middle
ここで、このオブジェクトに
add: 2 メッセージを送ります。

00:11:38.360 --> 00:11:43.280 align:middle
するとこの add: メソッドが選ばれて

00:11:43.560 --> 00:11:45.720 align:middle
このコードが実行されます。

00:11:46.280 --> 00:11:48.920 align:middle
Transcript を見て

00:11:49.760 --> 00:11:53.280 align:middle
このメソッドが実行されたか確認できます。

00:11:53.640 --> 00:11:57.400 align:middle
2 は追加されます。

00:11:57.640 --> 00:12:02.040 align:middle
super を使って Set クラスの
add: メソッドを使うからです。

00:12:02.840 --> 00:12:07.840 align:middle
こうして特定の集合を
スパイすることができます。

00:12:08.080 --> 00:12:09.560 align:middle
この行を使って。

00:12:11.200 --> 00:12:12.400 align:middle
まとめると

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

00:12:19.440 --> 00:12:23.840 align:middle
新しい機能を実装して
テストすることができます。

00:12:24.080 --> 00:12:29.400 align:middle
これらのリフレクティブなプリミティブで
言語拡張をすることができます。

00:12:30.200 --> 00:12:34.080 align:middle
ただし、リフレクションを使う上での
黄金律があります。

00:12:34.320 --> 00:12:38.800 align:middle
ドメインコードで不適切な使い方を
してはいけない、ということです。

00:12:39.040 --> 00:12:44.720 align:middle
ドメインコードでリフレクティブなコードを
使うことは制限すべきです。

00:12:45.080 --> 00:12:49.200 align:middle
リフレクションを使うと
カプセル化を破ることができます。

00:12:49.840 --> 00:12:51.000 align:middle
本当に

00:12:51.440 --> 00:12:54.640 align:middle
オブジェクトプログラミングの規律を
踏み越えることができてしまいます。

00:12:54.840 --> 00:12:58.520 align:middle
したがって、ツール構築に使うに
留めておくべきです。

