"Perlの"継承と委譲と

id:hideden:20051109をみて思い出したことがある。当時、Perlプログラマのバイトを始めて数週間かそれくらいだったと思う。OOPも、まあなんとか学習して、それを使いたくて仕方が無いお年頃だった。
そのときでかい案件があり、それをある程度のフレームワークで行いたかった。例えばDBへの接続なんかもあったりして、Apache::Sessionなんかも使う必要があったりして、当時としては結構大変な仕事だった。で、そのときに僕はCGI.pmを使ってセッション管理を行うことを考えた。すなわち、CGI.pmを継承させたクラスを作り、その中でSessionが正しいかどうかをチェックするというメソッドを追加することを考えた。
今となってはこれはありえない設計だとわかる。もちろん、この継承させたクラスはCGI.pmが許している操作は全て許している。それに、SessionCheckのメソッドを追加しただけなのだ。確かにis_aの関係は満たしている。だけども、この場合は委譲を使って実装するのがおそらく正しいのだ。
これを実装しているのがPerlというのがその理由にあるわけだが、これにはいくつかの意味がある。まず、PerlはAUTOLOADがあるので、Decoratorパターンを容易に作れるという点。これにより、わざわざ継承を使わずとも同じような動作は簡単に定義できる。従って、特に継承のメリットは無い。これはあくまで積極的な理由が無いということだけで、継承してはいけないという理由にはならない。
次に、Perlはメンバを確定させることが出来ない。すなわちJavaなどの言語では、メンバをクラス(の通常は一番上)で宣言する。だが、Perlはメンバの宣言は特にしなくても良い。すなわち、どんなメンバがクラス中に存在するかわからないのだ。ひょっとして引数で渡された名前のメンバを使用するかもしれないので、hogeという名前のメンバが存在するかどうかのチェックをしようと思って、hogeでソースを検索して見つからなかったから大丈夫というわけにも行かない。つまり、メンバを勝手に増やすのは極めて危険であって、また上記のAUTOLOADの関係もあってメソッドも勝手に増やして大丈夫かどうかの保証は無い。
さらに、これはOOP全般において言えることだが、継承はやり方によっては内部構造を知らないと作れないことがある。例えば既存のメンバの値を使ったりとかそういうことだ。
これらの理由で、Perlで標準クラスなんかを継承するのはあまりいただけない。当時の僕もそれをなんとなく理解し、最終的にはSledgeライクなフレームワークを作ることで作った。Perlは、privateなメンバとかを作るのも面倒だったりするので、大規模開発には向かないといわれたりもするわけだが、その理由の一つはこういうことだったりする。つまり、Perlで大きなクラスをきれいに書くのは、Javaできれいに書くよりも難しい。