動画で知るClass::C3とNEXTの違い

CatalystとかDBICを理解しようとすると頻繁に出てくるClass::C3。継承ツリーをどうにかするものらしいけど、挙動を把握するのは難しそうだなーという印象でした。

CatalystもそのうちNEXTからClass::C3ベースに変わるし」なんて話題が出ても、そもそもどっちも分かってないのでちんぷんかんぷんです。

したら、牧さんが去年のYAPCでClass::C3について語ってるじゃありませんか。これすげー、めちゃめちゃ分かりやすい。

PHPは多重継承サポートしてないし、それ以前にPerl使ってたころはそもそもOOP自体ちゃんと理解できてなかったので、多重継承なんて考えたのは初めて。そんな自分の印象としては、むしろNEXTの挙動の方が不自然なように思えます。

具体的にはこんな感じで使えばいいのかな。

#!/usr/bin/perl
use strict;
use warnings;

package MyApp::Filter;
use Class::C3;
INIT { Class::C3::initialize() }
sub filter {
    my ( $self, $arg ) = @_;
    return "[$arg]";
}

package MyApp::Filter::Reverse;
use base qw(MyApp::Filter);
sub filter {
    my ( $self, $arg ) = @_;
    $self->next::method( scalar reverse $arg );
}

package MyApp::Filter::Ucfirst;
use base qw(MyApp::Filter);
sub filter {
    my ( $self, $arg ) = @_;
    $self->next::method( ucfirst $arg );
}

package MyApp;
use base qw(
MyApp::Filter::Ucfirst
MyApp::Filter::Reverse
);

sub new {
    my $class = shift;
    bless {}, $class;
}

sub process {
    my ( $self, $arg ) = @_;
    return $self->filter( $arg );
}

package main;
use Perl6::Say;

my $obj = MyApp->new;
say $obj->process( 'hoge' );

ucfirstしてreverseして、最後にブラケットでくくって、出力は [egoH] になる。

MyAppの継承を

use base qw(
MyApp::Filter::Reverse
MyApp::Filter::Ucfirst
);

にすると、reverseしてからucfirstして、最後にMyApp::Filterするのは変わらなくて [Egoh] になる。いいねこれ。