継承(+委譲)について考えていきます
今回は、継承についての最初ということで、継承について現在私が考えているもの、これから求めていこうと思うものをざっくり出します
各項目の詳細な説明は次回以降ということにします。
(一応最低限の情報は載せるので実際にやるかどうかは気分しだいということで)
最近数学を見だしたばかりなので、数学用語等間違いがあれば主旨を変えない程度に変更する可能性は高いです
#1, 単一継承は多重継承の一形態ではないか
class C : public A, public B{}; //AとBを多重継承したC
class C : public A{}; //Aと無名の型を多重継承したC = 単一継承
//class C : public A, public 無名の型{/*中身は空*/}; //単一継承は←と同じと考える。Cは何も継承しなければ空集合とする
#2, 継承に使える要素
継承という仕組みに使えるのは集合のみだとします。(なぜかは、まだよくわからない)
これ以降、集合の特性を使います。
最も重要な特性は、"全ての集合は、ある条件を持つ"ということです
この条件のことを以後制約と呼びます
#3, 階層構造<-->制約 の変形
継承は、階層構造を持ちますが、これがどうにも扱いにくかったので制約の形に置き換えます
(相対パス(階層)<-->絶対パス(制約)のイメージ。継承で扱う階層は全て包含だとします)
ここに、ある集合の包含階層 A->B->C があるとします
これを制約表記(私の独自用語:おそらく何か専門用語があるはず)に置き換えます。(単に積集合を適用します)
$A : Aの制約を持つ = A = $Aの制約
$B : Aの制約とBの制約を持つ = A かつ B = $Bの制約
$C : Aの制約とBの制約とCの制約を持つ = A かつ B かつ C = $Cの制約
包含階層のAとCは階層が違うため演算ができません。
A->B->CにおけるCの制約は(A かつ B かつ C)であって、Cの制約は必要条件に過ぎないため、
Cの制約だけではCであることを表せず、AとCを同一の空間で扱うことができません
$A,$B,$Cなら、階層を気にせず扱うことができます
#4, Aであること及び、AかつBをオブジェクト指向に適用してみる
@1, Aならば、A'という必須なインターフェースを持つ
@2, Bならば、B'という必須なインターフェースを持つ
@3, Aならば、A''という(インターフェース以外の全ての)制約を満たす
@4, Bならば、B''という(インターフェース以外の全ての)制約を満たす
@1,@2,@3,@4が真のとき、
@5(AかつB)ならば (A'のインターフェースを持つ かつ B'のインターフェースをもつ)が真
@6(AかつB)ならば (A''の制約を満たす かつ B''の制約を満たす)が真
ここまではOKなのですが、次はどうでしょうか。
@7(A'のインターフェースを持つ かつ B'のインターフェースをもつ)ならば(AかつB) が真???
逆は必ずしも真ならずであり、@7は必ずしも真ではありません
@7は、@1,@2があってもなくても関係ないとき、つまりA'',B''が恒真のときのみ真です
@1も@3もAの必要条件です。
わざわざ分けたのは、プログラム言語がそうしていることが多いというだけです。
@1と@3をあわせると、"Aであるための全ての制約"と呼べます。
要はAであるための必要十分条件です
#5, 項目#4の、@1と@3の違い
インターフェースは、集合を分割する基準を持つことを表すことはできますが
分割された集合を選択することができません
例えば"赤色のもの"という型を作りたい時
X:"赤色かどうかという関数を持つ集合"と、Y:"赤色であるという集合"は同じ集合ではありません
X=赤い集合+赤くない集合 (赤色が何かということは知っている)
Y=赤い集合 (赤色が何かということは知っている)
制約という表現で言い換えると、
X=赤色かどうかという関数を持つという制約 という一つの制約を持つ集合
Y=赤色かどうかという関数を持つという制約と、赤色であるという制約という二つの制約を持つ集合
"赤色のもの"という型を作りたい時は、当然(XかYかでいえば)Yでなければいけません。
#6, AかつBとは、実装多重継承である
AとBが完全に別な時(独立している時?)、AかつBは実装多重継承を表します
しかし、現在のオブジェクト指向による継承の仕組みでは、インターフェースによる制約にしか対応していません。
だからインターフェース以外に制約があった時、現在のオブジェクト指向では実装多重継承は、
継承により必要な制約を引き継げないので、うまくいかないことが多いという予測が立ちます
項目#1より、単一継承は多重継承の特殊な形と考えた時、この問題は単一継承でも起こるはずです。
#7, インターフェース継承とは、AもしくはBの(IF以外の制約が)恒真のときのAかつBである
(c.制約 = (A.制約 && true))
オブジェクト指向言語によるインターフェースは実装のない関数を指します。
インターフェース以外の制約が恒真であることは、この実装のない関数、インターフェース継承で表すことができます
現在のオブジェクト指向ではこの"片側が恒真"という場合に必要なものを全てもっているので、
インターフェース継承はうまくいくことが多いと予測できます
#8, Aの全ての制約とBの全ての制約が同じ時、つまりAかつAの時はどうか
俗にis-aと呼ばれているものです。リスコフの置換原則も同じですかね?
現在のオブジェクト指向ではインターフェースは全て引き継がれるので、
おそらくインターフェース以外の全ての制約が同じであることをさしているのだと思います
Aが真のとき、AかつAは真になりますから、理屈としては正しいです
問題は、現在のオブジェクト指向(だけ)でこれを守るのは現実的に不可能であるということです
AとBがずれた時に検知する仕組みがないこと、そもそもAであることを示せないことが原因です
#9, Aの必要十分条件
オブジェクト指向では、Aの制約を表すことができません
ではここで仮に、Aという集合の制約をXとおいてみます
制約に含まれるものは全て、条件を満たすか満たさないかの2値、boolで表すことができます
条件がどれだけあっても、それらを全て積で重ね合わせれば、たった一つのboolとして表すことができます
Aという集合の制約Xは、一つのbool変数としておくことができます
全ての(少なくとも継承の可能な)要素は、一つのbool変数を持たなければいけません
bool変数とboolを返す関数は(多分数学的に)同等なので、boolを返す関数をおきましょう
オブジェクトがこの特殊な意味を持った boolを返す関数を含むのであれば、
インターフェースだけで "あるオブジェクトである"ということを示すことができます
Aであることが表すことができるようになれば、AかつBを表すことができるようになります
つまり、この仕組みを使えば、実装継承が可能になるはずです
うーーん。
まあそもそも全ての集合は、集合の条件をもつので、クラスを集合としておくのであれば、
全てのクラスはクラス(集合)の条件を表すboolを返す関数(もしくは同等の何か)を持たなければいけない、とするだけでも十分なのかもしれません。