Man is a Human? あるいはサブクラスと自由度

たまに,

class Human {}
class Man extends Human {}

なんて書かれてるけど,これ,ほんとかな?


いや,たとえば,marryTo/1ってのは常識的に考えてHumanのメンバなわけだけど,
少なくとも多くの国では異性としか結婚できないわけで,結局,こうなる.

class Human {}
class Man extends Human {
    Woman spouse;
    void marryTo(Woman woman) { spouse = woman; }
}
class Woman extends Human {
    Man spouse;
    void marryTo(Man man) { spouse = man; }
}

そう,marryTo/1の実装が分散しちゃうんだ.
でも,これは決してHumanには実装できない.

class Human {
    Human spouse;
    void marryTo(Human human) { spouse = human; }
}
class Man extends Human {
    Woman spouse;
    @Override void marryTo(Woman woman) { spouse = woman; }
}
class Woman extends Human {
    Man spouse;
    @Override void marryTo(Man man) { spouse = man; }
}

当然これはエラーだ.
継承ってのは自由度を増すことであって,こんなふうに自由度を減らすことはできない.
そしてこれはabstractを使っても同じ.

abstract class Human {
    abstract void marryTo(Human human);
}
class Man extends Human {
    Woman spouse;
    @Override void marryTo(Woman woman) { spouse = woman; }
}
class Woman extends Human {
    Man spouse;
    @Override void marryTo(Man man) { spouse = man; }
}

そう,HumanにmarryTo/1を実装することはできないんだ.


この問題は結局,型システムにowl:disjointWithみたいな要素がないことが原因なんだけど,
これを実装しようとすると,たとえばこういうふうになる.

enum Sex { MALE, FEMALE };
class IllegalSexException extends Exception {}
class Human {
    protected Sex sex;
    protected Human spouse;

    Human(Sex sx) { sex = sx; }
    Sex getSex() { return sex; }
    void marryTo(Human human) throws IllegalSexException {
        if (human.getSex() != sex) {
            spouse = human;
        } else {
            throw new IllegalSexException();
        }
    }
}
class Man extends Human {
    Man() { super(Sex.MALE); }
}
class Woman extends Human {
    Woman() { super(Sex.FEMALE); }
}

そう,システムの型システムを諦めて,自分で実装してしまう方法.
オントロジー的にはこれが一番正しいんだろうけど.なんせ不便.なんかExceptionとかはいてるし.


じゃあって,僕に考えつくのはこのぐらいなわけで.

interface Sex {}
interface Male extends Sex {}
interface Female extends Sex {}
class Human <TSex extends Sex, TComplementarySex extends Sex> implements Sex {
    Human<TComplementarySex, TSex> spouse;
    void marryTo(Human<TComplementarySex, TSex> human) { spouse = human; }
}
class Man extends Human<Male, Female> implements Male {}
class Woman extends Human<Female, Male> implements Female {}

これだとMaleとFemaleが相補的であることを誰も保証してくれないけど.
というか,なんか煩雑.


というわけで,困るわけです.どう書けばいいんだろう.
…あ,自由度の話書くの忘れた.