読者です 読者をやめる 読者になる 読者になる

Perl日記

PerlとかRubyとかPHPとかPythonとか

@ISAでの継承は読込が要る

会社の後輩に教えていて普通に分からなかったので赤裸々メモ。
わたしって、(ry


PerlでのOOのチュートリアルにperlbootとかperltootみていたら同一ファイル内での継承ばかりだったので、分割してみたら、動かなかった。

Animal.pm
package Animal;
sub speak {
  my $class = shift;
  print "$class speak.\n";
}
1;
Human.pm
package Human;
our @ISA = ('Animal');
1;
main.pl
package main;
use strict;
use warnings;
use Human;
Human->speak;

普段baseかparentでしか継承していなかったので、こういうところでボロが出た。

$ perl main.pl
Can't locate package Animal for @Human::ISA at main.pl line 4.
Can't locate package Animal for @Human::ISA at main.pl line 5.
Can't locate package Animal for @Human::ISA at main.pl line 5.
Can't locate object method "speak" via package "Human" at main.pl line 5.

はい。ごめんなさい。
まあ普通にbaseで継承すれば解決する話ではある。

package Human;
use base 'Animal';
1;

base.pmはそういえばrequireしてから呼び出し元の@ISAに押し込んでいるんだっけ、とか、
ダミアン・コンウェイ先生の本を見たりとか、
続・初めてのPerlとか見たりとか、
もう一回perlboot見たりとかした結果
@ISAに親クラス名入れるだけでは、その親メソッドを使える状態にはしてくれない。@ISAはただの親クラス名格納配列でありメソッド探索でしか使われないということがわかった。
(その辺はなぜか空気を読んでくれない)



だからまあ、

package Human;
our @ISA = ('Animal');
require 'Animal'; # add
1;

これでbaseでの継承と同じ。(BEGINでくくればもっと同じ)




ちなみにparentの-norequireは文字通りrequireしないので同じことが起こるので気をつける。

package Human;
use parent -norequire, 'Animal';
1;
Can't locate package Animal for @Human::ISA at main.pl line 4.
Can't locate package Animal for @Human::ISA at main.pl line 5.
Can't locate package Animal for @Human::ISA at main.pl line 5.
Can't locate object method "speak" via package "Human" at main.pl line 5.