『ポリモーフィズム』って何?
タイトルの問いについて、色んな人と話しながら自分なりの理解を書いていきます。
ぜひご意見を教えて下さい。
疑問のきっかけ
この本をchallenge-every-monthのコミュニティで輪読しており、今日は5章:オブジェクト指向プログラミングの章をやりました。
この章の冒頭で、「オブジェクト指向言語はカプセル化、継承、ポリモーフィズムという性質があると説明する人もいる」(そして「俺は違うと思うけどな」という事を凄く頑張って書いている)とあります。
ここでポリモーフィズムという言葉と初めて出会いました。そして、この言葉の示す所がいまいち分からなくなりました。
疑問をchallenge-every-monthのSlackで垂れ流していた所、 @budougumi0617 さんが相談に乗ってくださいまして、その結果何がきっかけなのか上手く説明できないのですが、オブジェクト指向言語の実装とポリモーフィズムという概念が上手く剥がれるという体験を得ました。
今回は混乱→理解のプロセスをなるべく端折らずに残しておこうと思います。
言葉の意味から探る
これがポリモーフィズムであるという端的な説明がなかったので、それはWikipediaに頼ることにしました。
ポリモーフィズム(英: Polymorphism)とは、プログラミング言語の型システムの性質を表すもので、プログラミング言語の各要素(定数、変数、式、オブジェクト、関数、メソッドなど)についてそれらが複数の型に属することを許すという性質を指す。ポリモルフィズム、多態性、多相性、多様性とも呼ばれる。対義語はモノモーフィズム (Monomorphism)、単態性、単相性で、プログラミング言語の各要素が唯一つの型に属するという性質を指す。
わからん。
これらを見ていると、継承と何が違うのかが分からない。
Clean Architectureにおける説明
Clean Architecture P.65から、サンプルコードと説明を引用します。
#include <stdio.h>
void copy(){
int c;
while((c=getchar()) != EOF)
putchar(c);
}
getchar()はSTDINから読み取りを行っている。だが、どのデバイスがSTDINなのだろうか? putchar()はSTDOUTに書き込みを行っている。だが、どのデバイスがSTDOUTなのだろうか? これらの関数はポリモーフィズムを実現している。その振る舞いがSTDINとSTDOUTの種類によって決まるからだ。
また、ポリモーフィズムのパワーという項(P.67)からも一部引用します。
ポリモーフィズムの優れた点は何だろうか? その魅力をきちんと評価するために、copyプログラムの例を再度考えてみたい。新しいIOデバイスが作成されたら、プログラムはどうなるのだろうか?(中略)
答えは、何も変更する必要はない! copyプログラムを再コンパイルする必要もない。なぜだろうか? copyプログラムのソースコードは、IOドライバのソースコードに依存していないからだ。(中略)
IOデバイスは、copyプログラムのプラグインになったのだ。
それでは、なぜUNIXはIOデバイスをプラグインにしたのだろうか? 1950年代後半に、我々がプログラムをデバイス非依存にすべきであることを学んだからだ。
ポリモーフィズムの例として挙げられたサンプルコードと説明からは、ポリモーフィズムによって、我々はデバイス非依存のプログラムを手に入れたと解釈することが可能そうです。
ポリモーフィズム : 同じ命令、異なる挙動=多態
@budougumi0617 さんに「結局継承と何が違うのか分からない」という話をした所、「ポリモーフィズムをオブジェクト指向言語で実現するための手段が継承」「ポリモーフィズムは継承を持っていない言語でも実現できる実装のメンタルモデルって感じ」という説明を受けました。
しばらくこの言葉がしっくり来るような来ないようなと悩んでいたのですが、しばらく上のサンプルコードなどを見ているうちに、ふと理解が降りてきました。
ポリモーフィズムとはデバイス非依存のプログラムが1例にあるような、1つの命令を書き換えずに、異なる挙動をさせるということだと理解しました。
そのための方法の1つがクラスを継承しオーバーライドすることであり、1つが標準入出力を使って入出力のデバイスの制御はOSの実装に任せることである。
継承の効果はポリモーフィズムだけではないから、継承とポリモーフィズムは全く別の概念です。しかしポリモーフィズムの実装のために継承は有力な手段です。この微妙に絡まった概念が理解をややこしくさせていたようです。
ポリモーフィズムは依存性逆転の話とも深い関わりがありそうですが、そこはまた別の機会に取っておこうかと思います。