The SUPER pseudo class is very slow!

SUPER疑似クラスを通じたメソッド呼び出しは非常に遅い。
もしベースクラスに手を加えることができるなら,空のフックメソッドをベースクラスに仕込んでおくことを考えたほうがいいかもしれない。

たとえば以下のケース:

# using SUPER
package BaseClass;
sub new{ bless {}, shift }

sub foo{
    my($self) = @_;
    # do something
}
package DerivedClass;
use parent -norequire => qw(BaseClass);

sub pre_foo{
    my($self) = @_;
    # do another thing
}

sub foo{
    my($self) = @_;
    $self->pre_foo();
    $self->SUPER::foo();
}

これは,以下のようにベースクラスのfoo()でpre_foo()を呼び出すようにしておき,サブクラスで拡張の余地を作っておくというコードでも全く同じ効果を持たせることができる。

# no SUPER
package BaseClass;
sub new{ bless {}, shift }

sub pre_foo{
    # empty hook
}

sub foo{
    my($self) = @_;
    $self->pre_foo();
    # do something
}

package DerivedClass;
use parent -norequire => qw(BaseClass);

sub pre_foo{
    my($self) = @_;
    # do another thing
}

もちろん,この書き換えにより,BaseClass->foo()そのものは内部でのメソッド呼び出しが増えて遅くなる。しかしDerivedClass->foo()を比較すると,圧倒的にこちらのバージョンのほうが高速である。
これは一つには,単純にメソッド呼び出し回数の違いもあるが,それ以上にSUPERメカニズム自体が非常に遅いということがある。
したがって,DerivedClassの使用が主であり,BaseClassに手を加えられるという状況なら,SUPERを使わないように書き換えるのは効果があると思われる。

ベンチマーク

Perl/5.10.0 on i686-linux

                Rate     SUPER/D non-SUPER/D non-SUPER/B     SUPER/B
SUPER/D      27675/s          --        -60%        -69%        -77%
non-SUPER/D  68922/s        149%          --        -22%        -43%
non-SUPER/B  88768/s        221%         29%          --        -26%
SUPER/B     120302/s        335%         75%         36%          --

SUPER/B(Base)とnon-SUPER/Bを比較すると,SUPER/Baseのほうが40%速い。しかし,SUPER/D(Derived)とnon-SUPER/Dを比較すると,non-SUPER/Dのほうが162%速い。つまり,BaseとDerivedの使用率が五分五分ならば,non-SUPERに書き換える価値はあると思われる。