こういうパッケージがあるとする.
# lib/Hoge/A.pm package Hoge::A; sub foo { return "I am A" } 1;
でもってこれを継承したBも作る:
# lib/Hoge/B.pm package Hoge::B; use parent qw(Hoge::A); sub foo { return "I am B" ) 1;
これだけだとただの継承だが,Aにもう1つメソッドを生やす:
package Hoge::A; sub foo { return "I am A" } sub call_foo { warn foo; } 1;
自分自身のfoo
を呼び出している.継承関係のおかげで,call_foo
はHoge::B
から使うことができる.
問題です
Hoge::B->call_foo
の結果はどうなるでしょう??
# test.pl use Hoge::A; use Hoge::B; Hoge::B->call_foo;
windymelt% perl -I lib ./test.pl I am A at lib/Hoge/A.pm line 7.
Bのfooは呼ばれなかった.
理由
warn $class->foo
ではなくwarn foo
と書いていたため.
A.pm
を修正してみる.
# lib/Hoge/A.pm package Hoge::A; sub foo { return "I am A" } sub call_foo { warn foo; ## ここを } 1;
# lib/Hoge/A.pm package Hoge::A; sub foo { return "I am A" } sub call_foo { my ($class) = @_; warn $class->foo; ## こうじゃ } 1;
するとHoge::B
のfoo
が呼ばれるようになる.
windymelt% perl -I lib ./test.pl I am B at lib/Hoge/A.pm line 7.
解説
->
オペレータがミソ.perldoc曰く:
サブルーチンがどのパッケージにあるかを Perl はどうやって知るのでしょうか? 矢印の左側を見ます; これはパッケージ名かオブジェクトへのリファレンス (つまりパッケージに bless された何か) のどちらかである必要があります。 どちらの場合も、それが Perl が探し始めるパッケージです。 もしそのパッケージに指定された名前のサブルーチンがないなら、Perl は そのパッケージの基底クラスを探し始めます; それを繰り返します。
->
を使わない場合,本来行われるべきメソッドの解決が行われず,ただのサブルーチン呼び出しになるため,サブルーチンを呼び出した箇所から参照可能な定義が勝手に選ばれてしまい,継承先でおかしな挙動を招いてしまう.
->
を使うことで初めて継承関係が解決されて実際にどの定義が呼び出されるべきかが決定される,と考えよう.
そもそも->
を使わない場合,もはやそれはメソッドの要件を満たしていないということになる.クラスのパッケージを第一引数に受け取るのがメソッドである.なので,引数が無いメソッドは->
を使わずに呼べるがこのような形を取るべきではない($class
だけ引数に取るべきだ).
->
オペレータは,Perlのオブジェクト指向らしさを一手に担っていると考えることもできる.よくできてるね.
まとめ
->
は継承を行うが,そうでないサブルーチン呼び出しは継承を行わない- オブジェクト指向するなら
->
を使うこと