今回はperlのモジュール使って書いたヨ、というわけではなくインスタンスのコピーってどうやってつくんの?っていう話題だ。
naoyaのはてなダイアリー - prototype.js でデザインパターン - Prototype
登録されてるインスタンスを連想配列から取り出して返却するのですが、そのときにそのまま取り出して返却するんではなく、インスタンスに実装されてる createClone() を呼び出して返却すると。createClone() の中ではインスタンスのコピーが行われます。
で、PerlサンプルのProduct.pmみてみると
sub clone {
my $self = shift;
my $class = ref($self);
bless {%{$self}}, $class;
}
sub createclone {
my $self = shift;
return $self->clone;
}
{%{$self}}がさっぱしわからん。なんでこれでインスタンス(ハッシュのリファレンス)のコピーが出来んの?
ってことを追求だ。
まず、インスタンスが異なるのかどうか、リファレンスをプリントして確認するためにmain.plをいじくる。
use strict;
use Manager;
use UnderlinePen;
use MessageBox;
my $manager = Manager->new;
my $upen = UnderlinePen->new('~');
$manager->register("strong message", $upen);
my $p11 = $manager->create("strong message");
my $p12 = $manager->create("strong message");
print $p11,"\n";
print $p12,"\n";
で実行。
$ perl main.pl
UnderlinePen=HASH(0x8dc6604)
UnderlinePen=HASH(0x8dc78dc)
おー、かわっとる。うーん、、、、、
素直に考えると
- $selfが%{$self}でリファレンスからハッシュへ
- それをさらにbless {%{$self}},$classで無名ハッシュでブレスして戻す
- だから、コピーされてる
んだろうなぁと思うんだけど。
試しにProduct.pmのcloneメソッドをこんな感じで変えてみる。
sub clone {
my $self = shift;
my $class = ref($self);
bless \%{$self}, $class;
}
でさっきとおなじmain.plを実行
$ perl main.pl
UnderlinePen=HASH(0x8491eb0)
UnderlinePen=HASH(0x8491eb0)
同じリファレンスだ。
ということはreturnされるときにコピーされるのかなぁ。うーん結局わからん。無名ハッシュ生成のメカニズムあたりをちゃんとチェックすれば解決するのか?
こういうメモリまわりを追っかける場合ってperl -dすればいいのかなぁ。
060412 追記
オブジェクト指向Perlマスターコースの3章に書いてあった
refを使ってオブジェクトの型を調べつつ、新しく生成したオブジェクトをハッシュ間の単純代入をするといいらしい。
%{objref2 = ref($objref1)->new()} = %{$objref1}
だから、こんな感じでオブジェクトはコピーできるそうなんだ。
このエントリは結城浩さんの本と、それに載っているサンプルをPerlで書いた例をみながら考えたことをメモってます。あとは、はてなの伊藤さんのjavascriptでの例も参考にしてます。
間違いの指摘とか、もっといいやり方教授してくれたらとても嬉しいゾ。