NEXTを試してたら頭が混乱してきた
PerlのコアモジュールにNEXTというのがあります。
NEXT - perldoc.perl.org
NEXT - Provide a pseudo-class NEXT (et al) that allows method redispatch - metacpan.org
とりあえずSYNOPSISのコードを実行してみたのがことの始まりでした。
環境はPowerBook G4にPerl 5.8.8で。
#!/usr/local/bin/perl use strict; use warnings; use NEXT; package A; sub A::method { print "$_[0]: A method?n"; $_[0]->NEXT::method() } sub A::DESTROY { print "$_[0]: A dtor?n"; $_[0]->NEXT::DESTROY() } package B; use base qw( A ); sub B::AUTOLOAD { print "$_[0]: B AUTOLOAD?n"; $_[0]->NEXT::AUTOLOAD() } sub B::DESTROY { print "$_[0]: B dtor?n"; $_[0]->NEXT::DESTROY() } package C; sub C::method { print "$_[0]: C method?n"; $_[0]->NEXT::method() } sub C::AUTOLOAD { print "$_[0]: C AUTOLOAD?n"; $_[0]->NEXT::AUTOLOAD() } sub C::DESTROY { print "$_[0]: C dtor?n"; $_[0]->NEXT::DESTROY() } package D; use base qw( B C ); sub D::method { print "$_[0]: D method?n"; $_[0]->NEXT::method() } sub D::AUTOLOAD { print "$_[0]: D AUTOLOAD?n"; $_[0]->NEXT::AUTOLOAD() } sub D::DESTROY { print "$_[0]: D dtor?n"; $_[0]->NEXT::DESTROY() } package main; my $obj = bless {}, "D"; $obj->method(); # Calls D::method, A::method, C::method $obj->missing_method(); # Calls D::AUTOLOAD, B::AUTOLOAD, C::AUTOLOAD # Clean-up calls D::DESTROY, B::DESTROY, A::DESTROY, C::DESTROY
コメントに書いてある順番でコールされるんだろうと思っていたらA::methodが呼ばれていない。A::DESTROYも呼ばれてない。
これが実行結果。
powerbook:~ takatoshi$ ./test_next.pl D=HASH(0x1801380): D method D=HASH(0x1801380): C method D=HASH(0x1801380): D AUTOLOAD D=HASH(0x1801380): B AUTOLOAD D=HASH(0x1801380): C AUTOLOAD D=HASH(0x1801380): D dtor D=HASH(0x1801380): B dtor D=HASH(0x1801380): C dtor
Aが無視されてる。@ISAの中身を表示してみることに。
#!/usr/local/bin/perl use strict; use warnings; use NEXT; package A; sub A::show { print "$_[0]: A isa @A::ISA?n"; $_[0]->NEXT::show() } sub A::method { print "$_[0]: A method?n"; $_[0]->NEXT::method() } sub A::DESTROY { print "$_[0]: A dtor?n"; $_[0]->NEXT::DESTROY() } package B; use base qw( A ); sub B::show { print "$_[0]: B isa @B::ISA?n"; $_[0]->NEXT::show() } sub B::AUTOLOAD { print "$_[0]: B AUTOLOAD?n"; $_[0]->NEXT::AUTOLOAD() } sub B::DESTROY { print "$_[0]: B dtor?n"; $_[0]->NEXT::DESTROY() } package C; sub C::show { print "$_[0]: C isa @C::ISA?n"; $_[0]->NEXT::show() } sub C::method { print "$_[0]: C method?n"; $_[0]->NEXT::method() } sub C::AUTOLOAD { print "$_[0]: C AUTOLOAD?n"; $_[0]->NEXT::AUTOLOAD() } sub C::DESTROY { print "$_[0]: C dtor?n"; $_[0]->NEXT::DESTROY() } package D; use base qw( B C ); sub D::show { print "$_[0]: D isa @D::ISA?n"; $_[0]->NEXT::show() } sub D::method { print "$_[0]: D method?n"; $_[0]->NEXT::method() } sub D::AUTOLOAD { print "$_[0]: D AUTOLOAD?n"; $_[0]->NEXT::AUTOLOAD() } sub D::DESTROY { print "$_[0]: D dtor?n"; $_[0]->NEXT::DESTROY() } package main; my $obj = bless {}, "D"; $obj->show(); #$obj->method(); # Calls D::method, A::method, C::method #$obj->missing_method(); # Calls D::AUTOLOAD, B::AUTOLOAD, C::AUTOLOAD # Clean-up calls D::DESTROY, B::DESTROY, A::DESTROY, C::DESTROY
こうなった。
powerbook:~ takatoshi$ ./test_next.pl Possible unintended interpolation of @A::ISA in string at ./test_next.pl line 8. Possible unintended interpolation of @C::ISA in string at ./test_next.pl line 19. D=HASH(0x1801380): D isa B C D=HASH(0x1801380): B isa Exporter D=HASH(0x1801380): C isa D=HASH(0x1801380): D dtor D=HASH(0x1801380): B dtor D=HASH(0x1801380): C dtor
Bの親クラスであるはずのAが出てこない上にExporterになってる。
????
このあとNEXTじゃなくてSUPERならどうだとかいろいろやってるうちに混乱の極地に陥りました。もう抜け出せません。なにか大切なことを見落としている気がしないでもないんだけどもうわかりません。。すごく気持ちが悪いんだけどこれ以上の深追いは事態を悪化させるだけな気がするので放置してみます。
きょうは寝付きが悪そうだ。
追記;
せっかくなんでもうちょっとだけ書く。
NEXTをSUPERにしたらこうなった。
最初の例。
powerbook:~ takatoshi$ ./test_super.pl D=HASH(0x1801380): D method D=HASH(0x1801380): C method Can't locate object method "method" via package "C" at ./test_super.pl line 16. D=HASH(0x1801380): D dtor D=HASH(0x1801380): B dtor (in cleanup) Can't locate object method "DESTROY" via package "B" at ./test_super.pl line 13.
@ISAを表示するやつ。
powerbook:~ takatoshi$ ./test_super.pl Possible unintended interpolation of @A::ISA in string at ./test_super.pl line 7. Possible unintended interpolation of @C::ISA in string at ./test_super.pl line 18. D=HASH(0x1801380): D isa B C D=HASH(0x1801380): B isa Exporter Can't locate object method "show" via package "B" at ./test_super.pl line 13. D=HASH(0x1801380): D dtor D=HASH(0x1801380): B dtor (in cleanup) Can't locate object method "DESTROY" via package "B" at ./test_super.pl line 15.
さらに追記:
わかった。布団の中で考えてたらわかった。
Bってコアモジュールがあるのを忘れてた。
B - perldoc.perl.org
use base qw( B );
ではここで定義したやつじゃなくてコアモジュールの方を継承してしまったのですね。
試しにBをEに変えてやってみた結果がこれ。
powerbook:~ takatoshi$ ./test_next.pl Possible unintended interpolation of @A::ISA in string at ./test_next.pl line 8. Possible unintended interpolation of @C::ISA in string at ./test_next.pl line 19. D=HASH(0x1801380): D isa E C D=HASH(0x1801380): E isa A D=HASH(0x1801380): A isa D=HASH(0x1801380): C isa D=HASH(0x1801380): D method D=HASH(0x1801380): A method D=HASH(0x1801380): C method D=HASH(0x1801380): D AUTOLOAD D=HASH(0x1801380): E AUTOLOAD D=HASH(0x1801380): C AUTOLOAD D=HASH(0x1801380): D dtor D=HASH(0x1801380): E dtor D=HASH(0x1801380): A dtor D=HASH(0x1801380): C dtor
納得。これでぐっすり眠れそうだ。
というか、SYNOPSIS変えた方がいいよね・・・。