WEBVTT

00:00:00.440 --> 00:00:01.480 align:middle
皆さん、こんにちは。

00:00:01.640 --> 00:00:03.400 align:middle
第 3 講目へようこそ。

00:00:03.560 --> 00:00:06.040 align:middle
今までに、継承や self

00:00:07.400 --> 00:00:10.400 align:middle
メッセージ探索を見てきました。
では super を見てみましょう。

00:00:10.840 --> 00:00:14.280 align:middle
最初に、super がレシーバーとなるような

00:00:14.880 --> 00:00:17.840 align:middle
メッセージ送信を見てみましょう。

00:00:18.360 --> 00:00:19.840 align:middle
super とは何でしょう？

00:00:20.120 --> 00:00:25.360 align:middle
ちょっと時間をかけて
次の2点について定義を考えてみましょう。

00:00:26.040 --> 00:00:28.200 align:middle
super は何を表わすのでしょうか？

00:00:30.400 --> 00:00:32.200 align:middle
super へメッセージが送られた時

00:00:32.360 --> 00:00:34.240 align:middle
メソッドはどのように探索されるでしょうか？

00:00:35.160 --> 00:00:36.560 align:middle
次の原則は

00:00:36.920 --> 00:00:39.200 align:middle
Pharo でも Java でも同じです。

00:00:39.560 --> 00:00:41.640 align:middle
ここで見ている例は

00:00:42.800 --> 00:00:46.240 align:middle
前の講義で見たものに似ています。

00:00:46.680 --> 00:00:49.360 align:middle
super が1つのメソッドで使われています。

00:00:52.320 --> 00:00:55.600 align:middle
何が起こるか、考えてみましょう。

00:00:56.440 --> 00:00:57.920 align:middle
A new bar については

00:00:59.560 --> 00:01:00.920 align:middle
問題ありません。

00:01:01.080 --> 00:01:03.120 align:middle
前と同じプロセスです。

00:01:03.320 --> 00:01:05.600 align:middle
メソッドが実行されて

00:01:06.160 --> 00:01:08.080 align:middle
foo は 10 を返します。

00:01:10.320 --> 00:01:13.440 align:middle
B new bar の場合について
ステップ毎に見ていきましょう。

00:01:15.560 --> 00:01:17.960 align:middle
メッセージ bar を

00:01:18.360 --> 00:01:20.720 align:middle
オブジェクト B new に送ります。

00:01:22.080 --> 00:01:24.840 align:middle
探索アルゴリズムはメソッド bar を

00:01:25.160 --> 00:01:27.160 align:middle
そのオブジェクトのクラスから
探していきます。

00:01:27.320 --> 00:01:29.800 align:middle
メソッド bar が見つかります。

00:01:30.880 --> 00:01:33.320 align:middle
そのメソッドがレシーバの上で実行されます。

00:01:34.000 --> 00:01:38.680 align:middle
この bar メソッドが
メソッドの上で実行されます。

00:01:40.040 --> 00:01:43.440 align:middle
ここで、「super bar」を
計算しなければなりません。

00:01:44.200 --> 00:01:46.640 align:middle
そして「self foo」も実行して
両者を足し合わせます。

00:01:46.880 --> 00:01:48.600 align:middle
「self foo」はできますね。

00:01:48.760 --> 00:01:53.400 align:middle
「self foo」はオブジェクト self に
メッセージ foo を送ります。

00:01:53.800 --> 00:01:55.600 align:middle
self は B new です。

00:01:56.640 --> 00:02:00.080 align:middle
可能なのは、クラス A の
foo メソッドだけです。

00:02:01.280 --> 00:02:03.160 align:middle
したがって、 self foo は 10 を返します。

00:02:04.840 --> 00:02:06.920 align:middle
「super bar」では

00:02:08.000 --> 00:02:09.720 align:middle
super がレシーバーです。

00:02:10.440 --> 00:02:12.920 align:middle
探索アルゴリズムは

00:02:13.120 --> 00:02:15.720 align:middle
レシーバー super があることで
変わってきます。

00:02:16.680 --> 00:02:19.840 align:middle
探索アルゴリズムは
キーワード super を含んでいるクラスの

00:02:20.320 --> 00:02:24.160 align:middle
スーパークラスから
メソッド bar を探し始めます。

00:02:25.080 --> 00:02:29.200 align:middle
super は、クラス B の
bar メソッドにあります。

00:02:29.640 --> 00:02:32.960 align:middle
メソッド bar を探す開始点は

00:02:33.120 --> 00:02:35.680 align:middle
B のスーパークラスである A になります。

00:02:36.240 --> 00:02:40.720 align:middle
したがって、このメソッドが見つかります。
そして実行されます。

00:02:41.000 --> 00:02:43.200 align:middle
foo が self に送られます。

00:02:43.360 --> 00:02:46.480 align:middle
self は常にレシーバーオブジェクトです。

00:02:46.880 --> 00:02:47.880 align:middle
つまり B new です。

00:02:48.120 --> 00:02:51.200 align:middle
したがって foo は
最初のオブジェクトに送られます。

00:02:51.560 --> 00:02:54.640 align:middle
これが実行された foo です。
10 が返されます。

00:02:56.800 --> 00:02:58.400 align:middle
10 + 10 は 20 です。

00:03:00.320 --> 00:03:02.480 align:middle
C new bar の場合には

00:03:02.920 --> 00:03:04.800 align:middle
ここに C new とあります。

00:03:05.120 --> 00:03:09.120 align:middle
それはクラス C のインスタンスです。
それにメッセージ bar を送ります。

00:03:09.800 --> 00:03:14.320 align:middle
クラス C で bar を探します。

00:03:14.640 --> 00:03:17.080 align:middle
見つかりません。
上位のクラスが探索されます。

00:03:17.480 --> 00:03:18.640 align:middle
B で見つかります。

00:03:18.800 --> 00:03:22.400 align:middle
それで B の bar が実行されます。

00:03:23.480 --> 00:03:27.960 align:middle
この bar は
2 つのメッセージ送信の合計です。

00:03:28.640 --> 00:03:31.480 align:middle
2つ目から始めてみます。

00:03:31.640 --> 00:03:34.640 align:middle
メッセージ foo を
オブジェクト self へ送ります。

00:03:34.880 --> 00:03:39.200 align:middle
self はまだ C new です。
メッセージ foo を送ります。

00:03:40.120 --> 00:03:42.760 align:middle
メソッドが見つかって、50 が返されます。

00:03:44.280 --> 00:03:45.880 align:middle
ここに 50 を置いておきます。

00:03:46.440 --> 00:03:50.960 align:middle
ここで、1つ目の部分である
super bar が必要になります。

00:03:51.240 --> 00:03:55.200 align:middle
メッセージ bar をsuper に送ります。
super は常にレシーバーです。

00:03:55.360 --> 00:03:58.280 align:middle
しかし探索アルゴリズムが変わります。

00:03:59.000 --> 00:04:04.240 align:middle
探索アルゴリズムはsuper を含むクラスの
スーパークラスから bar を探します。

00:04:05.320 --> 00:04:08.720 align:middle
それは B クラスの bar メソッドです。

00:04:09.000 --> 00:04:13.240 align:middle
アルゴリズムは B のスーパークラスである
A から bar を探し始めます。

00:04:13.880 --> 00:04:15.440 align:middle
bar はここにあります。

00:04:15.880 --> 00:04:17.360 align:middle
この bar が実行されます。

00:04:17.640 --> 00:04:20.920 align:middle
self はまだ C new です。
まだこのままです。

00:04:21.080 --> 00:04:22.440 align:middle
いつでもレシーバーです。

00:04:22.760 --> 00:04:24.440 align:middle
メッセージ foo を送ります。

00:04:24.600 --> 00:04:27.960 align:middle
結果は 50 です。ここに 50 が得られます。

00:04:28.280 --> 00:04:30.960 align:middle
50 + 50 は 100 です。

00:04:31.680 --> 00:04:32.920 align:middle
続くスライドで

00:04:33.360 --> 00:04:36.640 align:middle
探索アルゴリズムのより詳細を見て

00:04:36.800 --> 00:04:38.680 align:middle
深く学びましょう。

00:04:39.680 --> 00:04:42.880 align:middle
super は常にレシーバーを指します。

00:04:43.040 --> 00:04:45.120 align:middle
その点ではまさに self や

00:04:45.320 --> 00:04:47.200 align:middle
Java の this と似ています。

00:04:47.480 --> 00:04:52.440 align:middle
同様に、Java の super も this に似ています。
そして常にレシーバーを指します。

00:04:53.160 --> 00:04:57.520 align:middle
しかし、super にメッセージが送られた時には
探索アルゴリズムが変わって

00:04:57.680 --> 00:05:01.360 align:middle
実行されているメソッドを持つクラスの
スーパークラスから

00:05:01.800 --> 00:05:05.680 align:middle
メソッドを探し始めます。

00:05:06.040 --> 00:05:09.880 align:middle
従って、self と super は根本的に異なります。

00:05:10.320 --> 00:05:13.640 align:middle
self は動的ですが
super は静的です。

00:05:13.880 --> 00:05:15.520 align:middle
さらに説明をすると

00:05:17.080 --> 00:05:19.760 align:middle
foo が self に送られた時には

00:05:20.360 --> 00:05:24.240 align:middle
開発者は どの foo メソッドが実行されるか
全くわかりません。

00:05:24.880 --> 00:05:28.480 align:middle
同じクラスの foo かもしれませんし

00:05:29.120 --> 00:05:31.840 align:middle
今あるサブクラスの foo かもしれませんし

00:05:32.200 --> 00:05:35.640 align:middle
他の開発者がそのプログラムを実行する

00:05:35.920 --> 00:05:38.040 align:middle
直前に作った foo かもしれません。

00:05:38.720 --> 00:05:42.240 align:middle
bar メソッドの開発者が
self foo と書く時には

00:05:42.480 --> 00:05:45.640 align:middle
その開発者には どの foo が実行されるか
わからないのです。

00:05:46.080 --> 00:05:48.160 align:middle
これは便利な機能です。

00:05:48.480 --> 00:05:51.280 align:middle
つまり、開発者は新しいサブクラスを作って

00:05:51.440 --> 00:05:54.320 align:middle
クラス A の振る舞いを
変えることができるのです。

00:05:55.440 --> 00:05:58.120 align:middle
対照的に、super は静的です。

00:05:58.880 --> 00:06:03.400 align:middle
開発者が super foo と書く時には

00:06:04.000 --> 00:06:06.920 align:middle
プログラムを動かしたら
どの foo メソッドが実行されるであろうか

00:06:07.080 --> 00:06:09.560 align:middle
わかります。

00:06:09.840 --> 00:06:13.440 align:middle
super foo とここに書く時には

00:06:14.280 --> 00:06:16.360 align:middle
スーパークラス A の foo を指すのです。

00:06:16.880 --> 00:06:18.680 align:middle
これが変わることはありません。
super は静的なのです。

00:06:18.880 --> 00:06:21.640 align:middle
プログラムがどうコンパイルされるか
わかります。

00:06:22.080 --> 00:06:25.360 align:middle
残念なことに、書籍の中には

00:06:25.720 --> 00:06:28.160 align:middle
super に間違った定義を
しているものがあります。

00:06:28.320 --> 00:06:30.560 align:middle
ナンセンスな定義です。

00:06:30.920 --> 00:06:33.800 align:middle
ある本にあった定義はこうです。

00:06:34.320 --> 00:06:37.480 align:middle
その本では、super は

00:06:37.920 --> 00:06:42.280 align:middle
探索アルゴリズムに

00:06:42.440 --> 00:06:47.240 align:middle
レシーバーのクラスのスーパークラスから
メソッドを探すように指示する。

00:06:48.000 --> 00:06:50.480 align:middle
レシーバーのクラスのスーパークラス、と。

00:06:50.640 --> 00:06:54.360 align:middle
実際には、これは間違いです。
さきほど示した例で明らかなように。

00:06:54.800 --> 00:06:58.920 align:middle
aC をレシーバーとした場合には
そのクラスは C です。

00:06:59.720 --> 00:07:03.120 align:middle
したがって、レシーバーのスーパークラスとは
B のことになります。

00:07:04.040 --> 00:07:08.560 align:middle
ここにきて
super foo を実行する時には

00:07:08.960 --> 00:07:12.960 align:middle
もしその本に書いてあった定義の通りだとすると

00:07:13.640 --> 00:07:16.360 align:middle
メッセージ foo を 

00:07:17.640 --> 00:07:20.520 align:middle
super に送って実行されるのは

00:07:20.680 --> 00:07:24.320 align:middle
レシーバーのクラスのスーパークラスの
foo メソッドだということになります。

00:07:24.480 --> 00:07:27.480 align:middle
つまり、これです。

00:07:27.840 --> 00:07:30.520 align:middle
foo を super に

00:07:30.800 --> 00:07:34.480 align:middle
何度も何度も送って
無限ループになります。

00:07:35.680 --> 00:07:38.280 align:middle
つまりその定義は間違いです。

00:07:38.440 --> 00:07:43.760 align:middle
実際には、この例は完璧に動きます。

00:07:44.240 --> 00:07:46.640 align:middle
単純に、この定義が間違っているのです。

00:07:47.280 --> 00:07:49.480 align:middle
覚えておくべきことは

00:07:50.040 --> 00:07:52.440 align:middle
self は常にレシーバーを表わします。

00:07:52.680 --> 00:07:53.840 align:middle
super も同様です。

00:07:54.000 --> 00:07:58.040 align:middle
Java での this と super と同じです。

00:07:58.880 --> 00:08:01.160 align:middle
しかし、super はメソッド探索を変えます。

00:08:01.600 --> 00:08:05.000 align:middle
マッチを探し始めるのが

00:08:05.240 --> 00:08:07.320 align:middle
キーワード super を含んでいる
メソッドのクラスの

00:08:07.560 --> 00:08:12.160 align:middle
スーパークラスになります。

00:08:12.720 --> 00:08:15.240 align:middle
self は動的です。

00:08:15.640 --> 00:08:20.240 align:middle
開発者は self を使って
既存のクラスの振る舞いを拡張することができます。

00:08:20.440 --> 00:08:23.440 align:middle
メソッドを再定義するサブクラスを作ることで。

