ところが、そのないはずの隠蔽化を強制する仕組みがすでに発見されているのです。

ビンゴ中西のほげほげ Kansai.pm第8回ミーティングに行ってきました@荷造り中
そして、Perlのオブジェクト指向には 隠蔽化を強制する仕組みはない

いつか書こうと思っていたけど、ちょうどいい機会なので。

ここでは例として、name,uriという二つのインスタンス変数を持つオブジェクトを実装してみます。

InsideOut.pm
{
    package InsideOut;
    use strict;
    use warnings;
    my %objects;
    sub new {
        my $class = shift;
        bless \eval{ my $scalar }, $class;
    }
    sub DESTROY{
        my $self = shift;
        delete $objects{$self+0};
    }
    sub name{
       my $self = shift;
       $objects{$self+0}{name} = shift if @_;
       $objects{$self+0}{name};
    }
    sub uri{
       my $self = shift;
       $objects{$self+0}{uri} = shift if @_;
       $objects{$self+0}{uri};
    }
    1;
}
insideout.pl
use strict;
use warnings;
use InsideOut;
use Data::Dumper;

my $o = InsideOut->new();
$o->name("dankogai");
$o->uri("http://blog.livedoor.jp/dankogai/");
print $o->name, ",", $o->uri, "\n";
print Dumper $o;

ここで、insideout.plを実行してみると、以下のようになります。

% perl insideout.pl
dankogai,http://blog.livedoor.jp/dankogai/
$VAR1 = bless( do{\(my $o = undef)}, 'InsideOut' );

見ての通り、確かにaccessorを通した時には「インタンス変数」はアクセスできるのに、オブジェクトの中身は空っぽです。

ここで、InsideOut.pmの仕組みをよく見てみます。オブジェクトは空っぽのblessed scalar referenceです。Perlの場合、オブジェクトはblessed referenceであれば何でもOKなので、こうしています。

次にaccessorを見てみましょう。$objects{$self+0}{name}とは一体なんでしょう?$self+0に着目してみましょう。これは一体なんでしょうか?簡単なオブジェクトを作って実験してましょう。

% perl -MCGI -le '$q=CGI->new; printf "%s,%d,0x%x\n", $q, $q+0, $q+0'
CGI=HASH(0x1801180),25170304,0x1801180

そうなのです。リファレンスを数値コンテキストで評価すると、アドレスが返ってきます。これは各リファレンスに固有なので、オブジェクトのIDになります。accessorはこのIDをキーにしたハッシュ、%objectsにアクセスしています。

ところが、この%objectsはレキシカル変数です。InsideOut.pmの一番外側の{}の外からは全くアクセスできないのです。accessorを通すしかありません。これで、Perl 5でも隠蔽化が可能であることが示されました。

本来objectの中に入っているデータが外にある。それ故この方式で実装されたオブジェクトを、Inside-Out Objectと呼びます。

一つ留意しなければならないのは、この方式の場合、DESTROYを必ず実装しておく必要があります。データはオブジェクトの中にはないので、オブジェクトが破棄される際に、それに紐づいたデータは、%objectsが見えるスコープ中のDESTROYで削除してやる必要があるのです。

この方式はDamian Conwayのお気に入りで、それが嵩じて彼が実装したのがClass::Stdです。Inside-Out Objectにまつわる不便を、まとめて面倒みてくれるというものです。名前がClass::Stdとなっているところに彼のHubrisを感じずにはいられません。

詳しくは、上掲のPerl Best Practicesをご覧あれ。

Dan the Inside-Out Blogger