WEBVTT

00:00:00.600 --> 00:00:01.640 align:middle
みなさん、こんにちは。

00:00:01.800 --> 00:00:04.400 align:middle
今日は、私も含め、Pharo 開発者が

00:00:04.560 --> 00:00:08.360 align:middle
よくやってしまう間違いについて
お話します。

00:00:08.520 --> 00:00:12.520 align:middle
よくある間違いをより早く見つけて
修正する方法をお見せします。

00:00:13.560 --> 00:00:16.280 align:middle
ここにコードがあります。

00:00:16.440 --> 00:00:20.000 align:middle
実行すると、デバッガーが開いて

00:00:21.080 --> 00:00:24.880 align:middle
あるオブジェクトに
self メッセージが送られ

00:00:25.040 --> 00:00:27.680 align:middle
そのオブジェクトが self メッセージを
理解できない、と言ってきます。

00:00:27.840 --> 00:00:32.400 align:middle
self はメッセージではないと言いたいのですが
実際、とてもよく送られます。

00:00:32.560 --> 00:00:36.120 align:middle
コードのどこかに間違いがあるのです。

00:00:36.280 --> 00:00:38.680 align:middle
ちょっと見てみると

00:00:39.840 --> 00:00:41.800 align:middle
ピリオドが抜けていることに気付きます。

00:00:42.760 --> 00:00:45.800 align:middle
そのために実行中に

00:00:45.960 --> 00:00:50.360 align:middle
self が DiceHandle new の結果に
送られてしまいます。

00:00:50.520 --> 00:00:53.640 align:middle
DiceHandle クラスには
self メソッドはないので

00:00:53.800 --> 00:00:56.000 align:middle
デバッガーが開きます。

00:00:57.560 --> 00:01:02.240 align:middle
修正するには、最初の行の最後に
ピリオドを追加すれば良いです。

00:01:03.720 --> 00:01:06.600 align:middle
よくあるもう 1 つの問題は

00:01:06.760 --> 00:01:11.920 align:middle
繋がらないはずのメッセージが
繋がってしまっている場合です。

00:01:12.080 --> 00:01:16.280 align:middle
ここで「includes:ifTrue: は存在しない」
というエラーになります。

00:01:16.440 --> 00:01:19.400 align:middle
includes: も ifTrue: も存在しますが
includes:IfTrue: は存在しません。

00:01:19.560 --> 00:01:21.560 align:middle
よく見ると

00:01:21.880 --> 00:01:24.720 align:middle
本当に includes:ifTrue: メッセージが

00:01:24.880 --> 00:01:27.240 align:middle
送られている、という事実に気付きます。

00:01:27.720 --> 00:01:32.120 align:middle
レシーバー x に引数が 2 つ。
33 と ブロックです。

00:01:32.320 --> 00:01:34.320 align:middle
動きません。

00:01:34.480 --> 00:01:36.600 align:middle
Pharo がキーワードを見る時には

00:01:36.760 --> 00:01:39.120 align:middle
それに続く全てのキーワードを見ようとします。

00:01:39.280 --> 00:01:41.880 align:middle
全てのキーワードを取り込んで
それを 1 つのメッセージと見做します。

00:01:42.040 --> 00:01:44.160 align:middle
つまり、括弧が

00:01:44.320 --> 00:01:45.920 align:middle
欠けていたのです。

00:01:46.080 --> 00:01:49.480 align:middle
括弧があれば ifTrue: メッセージが
x includes: 33 の結果に送られます。

00:01:50.520 --> 00:01:54.440 align:middle
同様に
assert:includes: なんてありません。

00:01:54.600 --> 00:01:57.760 align:middle
意図しているのは
includes: の結果を assert: することなので

00:01:57.920 --> 00:02:01.440 align:middle
括弧が必要です。

00:02:02.040 --> 00:02:05.680 align:middle
1 つの式の中で
複数のキーワードメッセージを使う時は

00:02:05.880 --> 00:02:09.280 align:middle
躊躇せずに括弧を入れて

00:02:09.440 --> 00:02:13.200 align:middle
キーワードメッセージを分離してください。
さもなくば Pharo は 1 つのメッセージとして

00:02:13.360 --> 00:02:16.160 align:middle
くっつけてしまいます。

00:02:16.400 --> 00:02:18.600 align:middle
この例では

00:02:19.080 --> 00:02:23.320 align:middle
numbers に数値のコレクションが欲しいのですが

00:02:23.480 --> 00:02:27.720 align:middle
今のところ数はたった 1 つ
35 しかありません。

00:02:27.880 --> 00:02:33.000 align:middle
しかし、numbers の値を見ると
コレクションではなく

00:02:33.160 --> 00:02:35.840 align:middle
35 という数値になっています。
おかしいですね。

00:02:37.200 --> 00:02:41.240 align:middle
同様に、このコードでは

00:02:41.400 --> 00:02:45.120 align:middle
Dice クラスに new メッセージを送ると

00:02:45.280 --> 00:02:47.400 align:middle
整数 6 が得られます。

00:02:47.600 --> 00:02:49.200 align:middle
6 面のダイスではなく。

00:02:49.600 --> 00:02:52.200 align:middle
どちらの問題も、原因は同じです。

00:02:52.360 --> 00:02:54.360 align:middle
もっとしっかり見てみると

00:02:54.520 --> 00:02:57.880 align:middle
add: の後に yourself を追加すると

00:02:58.040 --> 00:02:59.520 align:middle
問題が解決します。
なぜかというと

00:02:59.720 --> 00:03:02.280 align:middle
add: は加えたオブジェクトを返すからです。

00:03:03.000 --> 00:03:05.560 align:middle
つまり、
OrderedCollection new add: 35

00:03:05.720 --> 00:03:07.920 align:middle
は、35 を返します。

00:03:08.080 --> 00:03:12.000 align:middle
最後に yourself を追加すれば
確実にレシーバーが得られます。

00:03:12.160 --> 00:03:14.200 align:middle
そうすれば numbers は
数値のコレクションになるはずです。

00:03:14.840 --> 00:03:15.960 align:middle
つまりこの場合の解決策は

00:03:16.160 --> 00:03:20.640 align:middle
各メッセージの最後に
yourself を追加することです。

00:03:21.560 --> 00:03:22.680 align:middle
また別の問題があります。

00:03:22.880 --> 00:03:26.000 align:middle
Book クラスの
borrow メソッドがあります。

00:03:26.160 --> 00:03:29.200 align:middle
実行すると

00:03:29.360 --> 00:03:32.040 align:middle
nil does not understand ifFalse:
というエラーメッセージが出ます。

00:03:32.200 --> 00:03:35.960 align:middle
つまり、ここでは ifFalse: メッセージを
nil に送ってしまっています。

00:03:36.120 --> 00:03:38.440 align:middle
どういうことかというと
inLibrary の値は nil つまり

00:03:38.600 --> 00:03:41.360 align:middle
変数のデフォルト値のままということです。

00:03:41.520 --> 00:03:46.360 align:middle
おそらくは、inLibrary は
初期化されていないのでしょう。

68 align:middle
00:03:46,520 --> 00:03:51,440
この変数にデフォルト値を設定してあげる
必要があります。

00:03:51.600 --> 00:03:53.960 align:middle
修正はとても簡単です。

00:03:54.120 --> 00:03:56.240 align:middle
initialize メソッドで

00:03:56.400 --> 00:04:01.880 align:middle
Book クラスのインスタンスを
生成するごとに

00:04:02.040 --> 00:04:04.480 align:middle
インスタンス変数 inLibrary に

00:04:04.640 --> 00:04:07.280 align:middle
True を入れればよいのです。

00:04:07.640 --> 00:04:09.680 align:middle
ただし、このコードを今実行すると

00:04:09.880 --> 00:04:12.280 align:middle
別のエラーメッセージが出ます。

00:04:12.440 --> 00:04:16.800 align:middle
Class True does not understand ifFalse:

00:04:17.520 --> 00:04:21.200 align:middle
原因はどこでしょう？
答えは、ここで代入したものが

00:04:21.360 --> 00:04:23.040 align:middle
クラスだからです。

00:04:23.200 --> 00:04:25.400 align:middle
真偽値ではなくクラスなのです。

00:04:26.040 --> 00:04:29.360 align:middle
真偽値の真の値は true です。
小文字で始まります。

00:04:30.480 --> 00:04:34.880 align:middle
クラス名は一般に大文字で始まります。

00:04:35.040 --> 00:04:37.280 align:middle
つまり True はクラスで

00:04:37.440 --> 00:04:41.240 align:middle
true は True クラスの
唯一のインスタンスです。

00:04:42.000 --> 00:04:43.920 align:middle
また別の問題があります。

00:04:44.240 --> 00:04:46.840 align:middle
Dice クラスの roll メソッドでは

00:04:47.000 --> 00:04:49.760 align:middle
ダイスを振ると

00:04:49.920 --> 00:04:52.520 align:middle
1 から面の数までの数が得られます。

00:04:52.680 --> 00:04:56.280 align:middle
ただし、この場合は
ダイスを振るとダイスが得られてしまいます。

00:04:56.440 --> 00:05:00.200 align:middle
出た目ではなく。

00:05:01.200 --> 00:05:05.520 align:middle
お見せしたメソッドは
下のほうのメソッドと等価です。

00:05:05.800 --> 00:05:10.760 align:middle
つまりリターンのないメソッドは
デフォルトで self を返すのです。

00:05:11.680 --> 00:05:15.680 align:middle
そのため roll メソッドが実行されると
振った結果として

00:05:15.840 --> 00:05:18.360 align:middle
ダイス自身を返します。

00:05:20.040 --> 00:05:24.120 align:middle
faces コレクションに atRandom を
送った結果ではなく。

00:05:24.920 --> 00:05:27.360 align:middle
同じ原因ですがちょっと違う例です。

00:05:27.800 --> 00:05:31.200 align:middle
Dice クラスに新しいメソッドを

00:05:31.360 --> 00:05:33.400 align:middle
定義しています。

00:05:33.560 --> 00:05:35.080 align:middle
Dice クラスに

00:05:35.240 --> 00:05:39.400 align:middle
Dice クラスのインスタンスを生成する
新しいメソッドを追加したいのですが

00:05:39.560 --> 00:05:43.120 align:middle
デフォルトの面の数を
ゼロに初期化しています。

00:05:44.120 --> 00:05:46.880 align:middle
Dice クラスに new メッセージを送ると

00:05:47.040 --> 00:05:49.480 align:middle
Dice クラス自身が返ってきます。

00:05:49.640 --> 00:05:52.120 align:middle
Dice クラスの
新しいインスタンスではなく。

00:05:53.040 --> 00:05:54.080 align:middle
どちらの場合でも

00:05:54.280 --> 00:05:56.760 align:middle
リターンがないために

00:05:56.920 --> 00:06:01.240 align:middle
デフォルトで self つまり
レシーバーを返しています。

00:06:01.400 --> 00:06:02.760 align:middle
クラスメソッドの場合
self はクラスです。

00:06:03.200 --> 00:06:04.920 align:middle
これらの問題を解決するには

00:06:05.560 --> 00:06:09.520 align:middle
返したい値を返すために
キャレットを追加するだけです。

00:06:11.200 --> 00:06:12.160 align:middle
次の問題は

00:06:12.600 --> 00:06:15.480 align:middle
このコードが実行されると

00:06:15.640 --> 00:06:20.520 align:middle
システムが固まってしまって
何もできなくなります。

00:06:20.680 --> 00:06:23.360 align:middle
Pharo と対話することが
できなくなります。

00:06:23.960 --> 00:06:25.120 align:middle
何が原因でしょう？

00:06:25.440 --> 00:06:29.000 align:middle
Dice クラスに新しいメソッドを

00:06:29.160 --> 00:06:31.920 align:middle
定義していますが

00:06:33.200 --> 00:06:36.280 align:middle
self は Dice クラスで

00:06:36.440 --> 00:06:40.960 align:middle
つまり self new は
自分自身を再帰的に呼び出しています。

00:06:41.320 --> 00:06:42.680 align:middle
ここで意図していることは

00:06:43.280 --> 00:06:46.640 align:middle
Dice クラスのスーパークラスの
デフォルトのインスタンス生成を

00:06:46.800 --> 00:06:48.560 align:middle
利用することで

00:06:48.720 --> 00:06:51.400 align:middle
それに何か処理を加えたいのです。

00:06:51.560 --> 00:06:53.920 align:middle
このように書くと
無限ループになります。

00:06:54.640 --> 00:06:57.680 align:middle
なので、ここでは self の代わりに
super と書き換える必要があります。

00:06:57.840 --> 00:07:01.720 align:middle
すると スーパークラスでの実装を
使うことができます。

00:07:03.000 --> 00:07:04.880 align:middle
理解していただきたいことは

00:07:06.520 --> 00:07:08.360 align:middle
我々は皆、たくさんの間違いをおかします。

00:07:08.520 --> 00:07:11.600 align:middle
今お見せした間違いは
全ての Pharo 開発者が

00:07:11.760 --> 00:07:13.800 align:middle
とても頻繁にやってしまうものです。

00:07:13.960 --> 00:07:17.880 align:middle
ありがちなのは

00:07:18.040 --> 00:07:20.360 align:middle
ピリオドの抜け

00:07:20.520 --> 00:07:22.240 align:middle
括弧の抜け

00:07:22.400 --> 00:07:24.480 align:middle
キャレットの抜け

00:07:24.640 --> 00:07:26.160 align:middle
そして yourself の抜けです。

00:07:26.840 --> 00:07:29.800 align:middle
問題の根本を見つけるために

00:07:30.000 --> 00:07:33.280 align:middle
デバッガーを使ってみてください。

00:07:33.440 --> 00:07:36.040 align:middle
すぐに閉じたりしないでください。

00:07:36.200 --> 00:07:39.520 align:middle
すぐに閉じてしまうと、問題を修正する
道を見失ってしまいます。

