Perl日記

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

SUPERは@ISAを探ってくれてるわけではない

これが動かなかったので調べたメモ。
strictはなしで。

 *{"Foo::aiueo"} = sub { print "aiueo.\n" }; # Fooクラスのaiueoメソッド

*{"Bar::new"} = sub { bless {}, "Bar" }; # Barクラスのコンストラクタ
push @Bar::ISA, "Foo"; # BarはFooを継承
*{"Bar::aiueo"} = sub { my $self = shift; $self->SUPER::aiueo(); }; # Fooのaiueoメソッドを呼ぶ

my $bar = Bar->new;
$bar->aiueo; # Barのaiueoを通してFooのaiueoを呼ぶ
Can't locate object method "aiueo" via package "main::SUPER" at - line 5.

$self->SUPER::methodという書き方がイディオムになってしまって
なんとなく$selfのクラスの@ISA読んで辿ってくれてるのかなーと思ってたけど、
まったくそんなことはなかった。

perldoc perlobj

It is important to note that "SUPER" refers to the superclass(es) of
the current package and not to the superclass(es) of the object.


SUPER は、オブジェクトのスーパークラスではなく、
カレントパッケージスーパークラスを参照するということに注意することは重要です。

http://perldoc.jp/docs/perl/5.10.0/perlobj.pod


上記のコードのカレントパッケージは指定してないのでmainだ。
だから"main::SUPER"ってエラーで怒られているってことか。

でもなんとかしたい

他のmroみたいなnextで何とかならないかなーと思ってやってみた。
第2回 mro:次のメソッドはどこ?:モダンPerlの世界へようこそ|gihyo.jp … 技術評論社

NEXT
use NEXT;
*{"Foo::aiueo"} = sub { print "aiueo.\n" };

*{"Bar::new"} = sub { bless {}, "Bar" };
push @Bar::ISA, "Foo";
*{"Bar::aiueo"} = sub { my $self = shift; $self->NEXT::aiueo(); };

my $bar = Bar->new;
$bar->aiueo;
Can't call NEXT::aiueo from main::__ANON__ at - line 6
Class::C3
use Class::C3;
*{"Foo::aiueo"} = sub { print "aiueo.\n" };

*{"Bar::new"} = sub { bless {}, "Bar" };
push @Bar::ISA, "Foo";
*{"Bar::aiueo"} = sub { my $self = shift; $self->next::aiueo(); };

my $bar = Bar->new;
$bar->aiueo;
Can't locate object method "aiueo" via package "next" at - line 6.
mro
use mro 'c3';
*{"Foo::aiueo"} = sub { print "aiueo.\n" };

*{"Bar::new"} = sub { bless {}, "Bar" };
push @Bar::ISA, "Foo";
*{"Bar::aiueo"} = sub { my $self = shift; $self->next::aiueo(); };

my $bar = Bar->new;
$bar->aiueo;
Can't locate object method "aiueo" via package "next" at - line 6.

うーんだめかー。
もはや理解もしないで手当たり次第にやってることがもろばれだ…。


まあ結論としては、packageでカレントパッケージを切り替えろ、ということでしょうかね。