1
00:00:00,600 --> 00:00:01,640
みなさん、こんにちは。

2
00:00:01,800 --> 00:00:04,400
今日は、私も含め、Pharo 開発者が

3
00:00:04,560 --> 00:00:08,360
よくやってしまう間違いについて
お話します。

4
00:00:08,520 --> 00:00:12,520
よくある間違いをより早く見つけて
修正する方法をお見せします。

5
00:00:13,560 --> 00:00:16,280
ここにコードがあります。

6
00:00:16,440 --> 00:00:20,000
実行すると、デバッガーが開いて

7
00:00:21,080 --> 00:00:24,880
あるオブジェクトに
self メッセージが送られ

8
00:00:25,040 --> 00:00:27,680
そのオブジェクトが self メッセージを
理解できない、と言ってきます。

9
00:00:27,840 --> 00:00:32,400
self はメッセージではないと言いたいのですが
実際、とてもよく送られます。

10
00:00:32,560 --> 00:00:36,120
コードのどこかに間違いがあるのです。

11
00:00:36,280 --> 00:00:38,680
ちょっと見てみると

12
00:00:39,840 --> 00:00:41,800
ピリオドが抜けていることに気付きます。

13
00:00:42,760 --> 00:00:45,800
そのために実行中に

14
00:00:45,960 --> 00:00:50,360
self が DiceHandle new の結果に
送られてしまいます。

15
00:00:50,520 --> 00:00:53,640
DiceHandle クラスには
self メソッドはないので

16
00:00:53,800 --> 00:00:56,000
デバッガーが開きます。

17
00:00:57,560 --> 00:01:02,240
修正するには、最初の行の最後に
ピリオドを追加すれば良いです。

18
00:01:03,720 --> 00:01:06,600
よくあるもう 1 つの問題は

19
00:01:06,760 --> 00:01:11,920
繋がらないはずのメッセージが
繋がってしまっている場合です。

20
00:01:12,080 --> 00:01:16,280
ここで「includes:ifTrue: は存在しない」
というエラーになります。

21
00:01:16,440 --> 00:01:19,400
includes: も ifTrue: も存在しますが
includes:IfTrue: は存在しません。

22
00:01:19,560 --> 00:01:21,560
よく見ると

23
00:01:21,880 --> 00:01:24,720
本当に includes:ifTrue: メッセージが

24
00:01:24,880 --> 00:01:27,240
送られている、という事実に気付きます。

25
00:01:27,720 --> 00:01:32,120
レシーバー x に引数が 2 つ。
33 と ブロックです。

26
00:01:32,320 --> 00:01:34,320
動きません。

27
00:01:34,480 --> 00:01:36,600
Pharo がキーワードを見る時には

28
00:01:36,760 --> 00:01:39,120
それに続く全てのキーワードを見ようとします。

29
00:01:39,280 --> 00:01:41,880
全てのキーワードを取り込んで
それを 1 つのメッセージと見做します。

30
00:01:42,040 --> 00:01:44,160
つまり、括弧が

31
00:01:44,320 --> 00:01:45,920
欠けていたのです。

32
00:01:46,080 --> 00:01:49,480
括弧があれば ifTrue: メッセージが
x includes: 33 の結果に送られます。

33
00:01:50,520 --> 00:01:54,440
同様に
assert:includes: なんてありません。

34
00:01:54,600 --> 00:01:57,760
意図しているのは
includes: の結果を assert: することなので

35
00:01:57,920 --> 00:02:01,440
括弧が必要です。

36
00:02:02,040 --> 00:02:05,680
1 つの式の中で
複数のキーワードメッセージを使う時は

37
00:02:05,880 --> 00:02:09,280
躊躇せずに括弧を入れて

38
00:02:09,440 --> 00:02:13,200
キーワードメッセージを分離してください。
さもなくば Pharo は 1 つのメッセージとして

39
00:02:13,360 --> 00:02:16,160
くっつけてしまいます。

40
00:02:16,400 --> 00:02:18,600
この例では

41
00:02:19,080 --> 00:02:23,320
numbers に数値のコレクションが欲しいのですが

42
00:02:23,480 --> 00:02:27,720
今のところ数はたった 1 つ
35 しかありません。

43
00:02:27,880 --> 00:02:33,000
しかし、numbers の値を見ると
コレクションではなく

44
00:02:33,160 --> 00:02:35,840
35 という数値になっています。
おかしいですね。

45
00:02:37,200 --> 00:02:41,240
同様に、このコードでは

46
00:02:41,400 --> 00:02:45,120
Dice クラスに new メッセージを送ると

47
00:02:45,280 --> 00:02:47,400
整数 6 が得られます。

48
00:02:47,600 --> 00:02:49,200
6 面のダイスではなく。

49
00:02:49,600 --> 00:02:52,200
どちらの問題も、原因は同じです。

50
00:02:52,360 --> 00:02:54,360
もっとしっかり見てみると

51
00:02:54,520 --> 00:02:57,880
add: の後に yourself を追加すると

52
00:02:58,040 --> 00:02:59,520
問題が解決します。
なぜかというと

53
00:02:59,720 --> 00:03:02,280
add: は加えたオブジェクトを返すからです。

54
00:03:03,000 --> 00:03:05,560
つまり、
OrderedCollection new add: 35

55
00:03:05,720 --> 00:03:07,920
は、35 を返します。

56
00:03:08,080 --> 00:03:12,000
最後に yourself を追加すれば
確実にレシーバーが得られます。

57
00:03:12,160 --> 00:03:14,200
そうすれば numbers は
数値のコレクションになるはずです。

58
00:03:14,840 --> 00:03:15,960
つまりこの場合の解決策は

59
00:03:16,160 --> 00:03:20,640
各メッセージの最後に
yourself を追加することです。

60
00:03:21,560 --> 00:03:22,680
また別の問題があります。

61
00:03:22,880 --> 00:03:26,000
Book クラスの
borrow メソッドがあります。

62
00:03:26,160 --> 00:03:29,200
実行すると

63
00:03:29,360 --> 00:03:32,040
nil does not understand ifFalse:
というエラーメッセージが出ます。

64
00:03:32,200 --> 00:03:35,960
つまり、ここでは ifFalse: メッセージを
nil に送ってしまっています。

65
00:03:36,120 --> 00:03:38,440
どういうことかというと
inLibrary の値は nil つまり

66
00:03:38,600 --> 00:03:41,360
変数のデフォルト値のままということです。

67
00:03:41,520 --> 00:03:46,360
おそらくは、inLibrary は
初期化されていないのでしょう。


68
00:03:46,520 --> 00:03:51,440
この変数にデフォルト値を設定してあげる
必要があります。

69
00:03:51,600 --> 00:03:53,960
修正はとても簡単です。

70
00:03:54,120 --> 00:03:56,240
initialize メソッドで

71
00:03:56,400 --> 00:04:01,880
Book クラスのインスタンスを
生成するごとに

72
00:04:02,040 --> 00:04:04,480
インスタンス変数 inLibrary に

73
00:04:04,640 --> 00:04:07,280
True を入れればよいのです。

74
00:04:07,640 --> 00:04:09,680
ただし、このコードを今実行すると

75
00:04:09,880 --> 00:04:12,280
別のエラーメッセージが出ます。

76
00:04:12,440 --> 00:04:16,800
Class True does not understand ifFalse:

77
00:04:17,520 --> 00:04:21,200
原因はどこでしょう？
答えは、ここで代入したものが

78
00:04:21,360 --> 00:04:23,040
クラスだからです。

79
00:04:23,200 --> 00:04:25,400
真偽値ではなくクラスなのです。

80
00:04:26,040 --> 00:04:29,360
真偽値の真の値は true です。
小文字で始まります。

81
00:04:30,480 --> 00:04:34,880
クラス名は一般に大文字で始まります。

82
00:04:35,040 --> 00:04:37,280
つまり True はクラスで

83
00:04:37,440 --> 00:04:41,240
true は True クラスの
唯一のインスタンスです。

84
00:04:42,000 --> 00:04:43,920
また別の問題があります。

85
00:04:44,240 --> 00:04:46,840
Dice クラスの roll メソッドでは

86
00:04:47,000 --> 00:04:49,760
ダイスを振ると

87
00:04:49,920 --> 00:04:52,520
1 から面の数までの数が得られます。

88
00:04:52,680 --> 00:04:56,280
ただし、この場合は
ダイスを振るとダイスが得られてしまいます。

89
00:04:56,440 --> 00:05:00,200
出た目ではなく。

90
00:05:01,200 --> 00:05:05,520
お見せしたメソッドは
下のほうのメソッドと等価です。

91
00:05:05,800 --> 00:05:10,760
つまりリターンのないメソッドは
デフォルトで self を返すのです。

92
00:05:11,680 --> 00:05:15,680
そのため roll メソッドが実行されると
振った結果として

93
00:05:15,840 --> 00:05:18,360
ダイス自身を返します。

94
00:05:20,040 --> 00:05:24,120
faces コレクションに atRandom を
送った結果ではなく。

95
00:05:24,920 --> 00:05:27,360
同じ原因ですがちょっと違う例です。

96
00:05:27,800 --> 00:05:31,200
Dice クラスに新しいメソッドを

97
00:05:31,360 --> 00:05:33,400
定義しています。

98
00:05:33,560 --> 00:05:35,080
Dice クラスに

99
00:05:35,240 --> 00:05:39,400
Dice クラスのインスタンスを生成する
新しいメソッドを追加したいのですが

100
00:05:39,560 --> 00:05:43,120
デフォルトの面の数を
ゼロに初期化しています。

101
00:05:44,120 --> 00:05:46,880
Dice クラスに new メッセージを送ると

102
00:05:47,040 --> 00:05:49,480
Dice クラス自身が返ってきます。

103
00:05:49,640 --> 00:05:52,120
Dice クラスの
新しいインスタンスではなく。

104
00:05:53,040 --> 00:05:54,080
どちらの場合でも

105
00:05:54,280 --> 00:05:56,760
リターンがないために

106
00:05:56,920 --> 00:06:01,240
デフォルトで self つまり
レシーバーを返しています。

107
00:06:01,400 --> 00:06:02,760
クラスメソッドの場合
self はクラスです。

108
00:06:03,200 --> 00:06:04,920
これらの問題を解決するには

109
00:06:05,560 --> 00:06:09,520
返したい値を返すために
キャレットを追加するだけです。

110
00:06:11,200 --> 00:06:12,160
次の問題は

111
00:06:12,600 --> 00:06:15,480
このコードが実行されると

112
00:06:15,640 --> 00:06:20,520
システムが固まってしまって
何もできなくなります。

113
00:06:20,680 --> 00:06:23,360
Pharo と対話することが
できなくなります。

114
00:06:23,960 --> 00:06:25,120
何が原因でしょう？

115
00:06:25,440 --> 00:06:29,000
Dice クラスに新しいメソッドを

116
00:06:29,160 --> 00:06:31,920
定義していますが

117
00:06:33,200 --> 00:06:36,280
self は Dice クラスで

118
00:06:36,440 --> 00:06:40,960
つまり self new は
自分自身を再帰的に呼び出しています。

119
00:06:41,320 --> 00:06:42,680
ここで意図していることは

120
00:06:43,280 --> 00:06:46,640
Dice クラスのスーパークラスの
デフォルトのインスタンス生成を

121
00:06:46,800 --> 00:06:48,560
利用することで

122
00:06:48,720 --> 00:06:51,400
それに何か処理を加えたいのです。

123
00:06:51,560 --> 00:06:53,920
このように書くと
無限ループになります。

124
00:06:54,640 --> 00:06:57,680
なので、ここでは self の代わりに
super と書き換える必要があります。

125
00:06:57,840 --> 00:07:01,720
すると スーパークラスでの実装を
使うことができます。

126
00:07:03,000 --> 00:07:04,880
理解していただきたいことは

127
00:07:06,520 --> 00:07:08,360
我々は皆、たくさんの間違いをおかします。

128
00:07:08,520 --> 00:07:11,600
今お見せした間違いは
全ての Pharo 開発者が

129
00:07:11,760 --> 00:07:13,800
とても頻繁にやってしまうものです。

130
00:07:13,960 --> 00:07:17,880
ありがちなのは

131
00:07:18,040 --> 00:07:20,360
ピリオドの抜け

132
00:07:20,520 --> 00:07:22,240
括弧の抜け

133
00:07:22,400 --> 00:07:24,480
キャレットの抜け

134
00:07:24,640 --> 00:07:26,160
そして yourself の抜けです。

135
00:07:26,840 --> 00:07:29,800
問題の根本を見つけるために

136
00:07:30,000 --> 00:07:33,280
デバッガーを使ってみてください。

137
00:07:33,440 --> 00:07:36,040
すぐに閉じたりしないでください。

138
00:07:36,200 --> 00:07:39,520
すぐに閉じてしまうと、問題を修正する
道を見失ってしまいます。
