
Shiroさん、いい質問です。
404 Blog Not Found:perl - Yet Another Way to Add Singleton Methodsちょっと疑問。この実装で、$fooが不要になった時に$fooおよびシングルトンメソッドのsubの実体はGCされるのでしょうか。
結論を先に言うと、きちんとされます。というのか、この場合それを手でやっているわけです。そして、それを手でやっている箇所がDESTROY。
sub DESTROY { my $self = shift; $DEBUG and carp "Destroing $self"; delete $Method{ $self + 0 }; }
実はこのmethodは、名前に反して「ゴミ捨て」そのものはしません。Perl5のGCは単純なReference Counterなので、あるobjectのreference countが0になったらその場で捨てられます。
そしてこのDESTROYというmethodは、もし定義されていたら、ゴミ捨て寸前に実行されるという関数なのです。だからもう少し名が体を表すようにすると、GC_PREHOOKという名前にでもなるでしょうか。
さて、ここではなぜわざわざDESTROYを定義してあるか?それは、このclassがあるクラスに対する"shadow object"とでもいうべきものをPrivate Hashの中に保持しているからです。そのshadow objectが、まさにsingleton methodなのですが、何もしないとそのPrivate Hashの中にずっと残ってしまいます。
そこでDESTROYの登場です。これは、元のobjectが破棄される寸前に呼ばれます。その時に、delete $Method{ $self + 0 }でhash entry -- singleton methodを破棄しているわけです。
Reference Counterというと、GCのテクニックとしては実は結構原始的なのですが、このようにUser Land側でGCのふるまいを調整できるという利点もあって私は結構好きです。
また、Perl5のclosureの実装は、このGCの仕組みとも密接に関係しています。
sub make_adder{ my $init = shift; # refcount($init) = 1 return sub { $init++; # refcount($init) = 2 } } # refcount($init) = 1 my $subref = make_adder(0); $subref->(); undef $subref # refcount($init) = 0 -- goodbye!
というわけです。実はどうやらこのclosureの実装も、有名なs///eeと同じく、意図されて設計された仕様ではなくて「発見」された仕様のようです。
Perlの世界では、結構このように「発見」によって確立されたテクニックも多いところが、私にはむしろ言語の豊穣さに思えます。実はinside-out objectも、明らかに「発見」されたものです。この方法で、Perlでも完全なobject privacyが確保できてしまうのですから。ラクダ本にも「まだ」書いてありません。
Perl6では、この辺の発見されたノウハウは、「ふつうに」使えるようになります。GCももっと洗練されたものが導入される予定です。しかしPerl6の世になっても、新しい技が発見されつづけると思います。またそれを許す言語であることを、開発者たちは皆望んでいます。
言語は作った人が想像もしなかった使われ方に耐えてなんぼなのかも知れませんね。
Dan the Garbage Accumulator
この手の方法でよく問題になるのはクロージャが元オブジェクトへの参照を掴んでしまって循環参照が起きることなのですが、よく見たら元の例ではクロージャは元オブジェクトを掴んでいませんね。
PerlのOOPだと元オブジェクトを引数から取るスタイルなので問題になることが少ないのでしょうか。