多態という観点で各種のオブジェクトシステムを分類するよ
「全オブジェクト指向システム入場!」というネタを思い付いた。「ラムダ計算は生きていた!! 更なる研鑚を積みCommonLispが甦った!!! 読み方不定!! CLOSだァ――――!!!」「メッセージパッシングはすでに我々が完成している!! デザインパターンの宝庫Smalltalkだァ――――!!!」「コンパイル時に既にチューリング完全!! 変態言語代表 C++だァッ!!!」「多言語混合なら我々の単純さがものを言う!! Cで使えるオブジェクトライブラリ gobject!!!」
まだまだ続けられそうだけど、続ける事に意味を感じないのでこれぐらいにしておく。
オブジェクト指向の本質が多態だと仮定すると、どうやって多態を実現するのか、という観点から各オブジェクトシステムを分類する事ができる。多態とは要するに、オブジェクトに応じて適切な処理を呼び出す、という事になる。これにはいくつかのやり方がある。いろいろ考えてみたが、大きく分けると2種類に分類できそうに思う。
- オブジェクトと処理をどうにかして結合しておく。
- 型を見てもっとも適切と思われるメソッドを呼び出す。
この観点から、Ruby,JavaScript,CLOS,Haskellを分類すると、RubyとJavaScriptは1番、CLOS,Haskellは2番に分類される。
まず、Rubyの場合、オブジェクトは自分自身のクラスを知っており、クラス定義時にメソッドも定義してある。(動的にメソッドを追加したりもできるけど。)あるクラスのオブジェクトをnewしたら、newしたクラスのメソッドを持ったオブジェクトが出来る。このようにして、リストに対してもハッシュに対してもsizeという同名のメソッドで要素数を求めることが出来る。
これを書くためにちょっと調べてみたけど、Rubyではレシーバ以外の情報で呼び出すメソッドの実体を変えたかったら(つまり、メソッドのオーバーロードがしたかったら)、自分で引数を見てディスパッチしないといけないようだ。
次にJavaScript。JavaScriptの場合はメソッドを持ったオブジェクトを定義しておいて、それをnewでコピーして使うので、このコピー時にメソッドが引き継がれる…はず。JavaScriptは使ったことがないのでちょっと自信がないけど、プロトタイプベースというのはそういう事なのだと思う。
次にCLOS。CLOSの場合(というか、CLOSライクと言われてるGaucheのオブジェクトシステムでは)はメソッド(C/C++的イメージでは関数と考えた方が良い)を定義すると、その名前で総称関数が定義される。例えば、「define-method size 」とすると実際にはsize-listという関数が定義され、「define-method size
Haskellの場合はCLOSと似てる。似てるけど、型推論を行って戻り値の型まで推論して曖昧性の解消をしている。これがないとモナドの多態性が実現できないので、Scheme使いとしてはちょっと羨ましい。(型推論する代わりに手書きで型を書くという手は、やはりくやしい。)
C++とかJavaはメソッドのオーバーロードが出来た気がするので、1と2のハイブリッドな感じだろうか。ただ、ハイブリッドにしたからといって強力になるかというとそういうことはなく、曖昧性の解消という観点で見ると、2の場合と能力は変わらない(もしくは負けているかもしれない)。
処理とデータを分離する、という点において2のCLOSやHaskellのやり方が美しいと思うのだが、世間的には今のところ1の方が人気である。クラスが構造体の素敵な拡張として捉えられる、というあたりにその人気の原因があったりするのではないだろうかと考えている。(プロトタイプベースはあんま人気ないし。JavaScriptはブラウザに乗ってたから人気だけど、それ以外で人気のあるプロトタイプベースの言語を知らない。)
まぁ、ある方法で他の方法を実現できたりするので、分類に重要な意味があるかというと、あんまりないような気もする。昼飯にラーメンを食べるかうどんを食べるか、という程度の違いかな。とは言え、他の言語でどうなってるかとか、調べてみると面白いかもしれない。
あと、多態というのは曖昧性を適切に処理系側で解消させるということで、曖昧なプログラムを書く方が書きやすいとかそういう話につながっていくのではないだろうか、とか考えた。