リクエストディスパッチの構造
形式化/抽象化をしないと、いつまでたってもハッキリしないグダグダ状態が続く。リクエストディスパッチの基本は、いちおう「集合と論理の練習問題: ツリー状の集合族 - 檜山正幸のキマイラ飼育記 」に書いた。
僕はオブジェクト指向は好きじゃないが、結果的にはオブジェクト指向っぽい話になる。「結果的」は今回のキーワードだ、as-a-result を、「結果的」を意味する形容詞に使おう。
Catyの型システムはサブタイプ/スーパータイプの宣言はないが、「結果的にサブタイプ」(as-a-result subtype、subtype as-a-result)はある。ダックタイピングと言ってもいい。リソースクラスのあいだに継承はないが、「結果的に継承」とか「結果的にサブクラス」という関係はある。この「結果的に=意図してないが」というのは非常に重要な概念だと思う。
「結果的に継承」、「結果的にサブクラス」を定式化するために、3つの集合を考える。
- 集合C -- クラス識別子の集合。Cの要素を単にクラスとも呼ぶ。Catyのリソースクラスに対応。
- 集合S -- クラスのメソッドセレクタの集合。Sの要素はメソッドそのものではなくて、メソッドを起動するための記号。Catyでは、アクションインボーカーと言っているヤツ。
- 集合U -- Catyでは、パス文字列全体の集合。すべてのリソースインスタンスの集合と言っても同じ。
抽象的なセッティングでは:
- C -- 有限集合。それ以上の制限も意味もない。空でもいいが、空だと議論する意味が無い。
- S -- 普通は無限集合。有限でもいい。空ではない。
- U -- 普通は無限集合。有限でもいい。空ではない。
構造を与えるのは、Inst:C→Pow(U) と、A:C→Pow(S) という関数。r∈C に対して、Inst(r) は |r| と略記する。クラスrのインスタンスの集合が |r| 。InstとAの条件は:
- r∈C に対して、 |r| は空ではない。
- r, s∈C に対して、 r≠s ならば、|r|⊂|s|、|s|⊂|r|、|r|∩|s|=0(空集合)のどれかが成立する。
- r∈C に対して、A(r) は有限集合、空でもよい。
「rはsのサブクラス」と「rはsをオーバーライドする」を次のように定義する。
- rはsのサブクラス ⇔ |r|⊂|s|
- rはsをオーバーライドする ⇔ (|r|⊂|s| かつ A(r)∩A(s)≠0)
(i, s)∈U×S をリクエストと呼ぶ。
- r |= (i, s) ⇔ (i∈|r| かつ s∈A(r))
次が成立する。
- (r |= (i, s) かつ r' |= (i, s) となるリクエストが存在する) ⇔ (rはr'をオーバーライドするか、r'はrをオーバーライドする)
以上で定義した「サブクラス」「継承」「オーバーライド」は、いずれも「結果的に(as-a-result)」であって、宣言するもの(ノミナル)ではない。構造的っちゃそうだが、やはり「意図せずに」という感じが強い。