アクセサ(2) AUTOLOAD でアクセサ

普通にアクセサメソッドを宣言していたのでは、無駄が多いのが難点でした。
1つ考えたのが、AUTOLOADで存在しないメソッドが呼ばれたらアクセサとする方法です。

package Person;
 
sub new {
    my $class = shift;
    my $self = {
        name => "Somebody",
        age => 0,
    };
    bless $self, $class;
}
 
sub DESTROY { }
 
sub AUTOLOAD {
    my $self = shift;
    my $meth = (split "::", $AUTOLOAD)[-1];
    if (@_) { $self->{$meth} = shift; }
    return $self->{$meth};
}
sub introduce {
    my $self = shift;
    print "I am " . $self->name();
    print ", " . $self->age() . " years old.\n";
}
 
package main;
$man = Person->new();
$man->introduce();
 
$man->name("Taro");
$man->age(10);
$man->introduce();

この方法なら、いくら属性が増えてもいちいちアクセサメソッドを書き足す必要がありません。最初に作ったコードと全く同じように動作します。
ただし、難点がいくつかあります。

  • AUTOLOAD は遅い
    • アクセサは頻繁に呼ばれるメソッドなので、実行速度は速いほうが良い。
  • アクセサ名をtypo(打ち間違い)してもエラーにならないので、バグが発生しやすい。
    • 例えば $man->ega(10); と書いていてもエラーにならず $self->{ega} に 10 をセットしてしまう。
  • UNIVERSAL::can でアクセサの存在が確かめられない。
    • AUTOLOAD されるメソッドは UNIVERSAL::can を使っても存在を確かめる事はできません。

うーん、あまり現実的ではなさそうですね。(^_^;)