🎃

オブジェクト指向を動物の例で説明するのは有害ではないか

2024/09/16に公開2

オブジェクト指向の説明で、生き物を使った例を時々見かける気がします。こういうやつです:

interface Animal {
    ...
}
class Dog implements Animal {
    ...
}
class Cat implements Animal {
    ...
}

こういう 「生き物のように感情移入しやすい対象」を例として使うとプログラミング技法の本質を見誤るのではないか? という話をします。

カプセル化

多くのクラスベースオブジェクト指向言語は、アクセス修飾子によってメンバーの公開範囲を制御できます。カプセル化というやつです。

class User {
    public String name; // 公開
    private int hidden_info; // 非公開
}

さて、publicなメンバーが誰でも見られるのはいいとして、privateなメンバーの公開先はどうあるべきでしょうか?候補は次の2つとなるでしょう。

  1. 公開範囲は「自分だけ」つまりprivateメンバーを触れるのは this/self 経由のみとする。
  2. 同じクラスであれば他のインスタンスのprivateメンバーでも触れるものとする。

クラスベースのオブジェクト指向を学んだ者であれば誰もが考えたことのあるこの疑問に、あなたはどう答えますか?あるいは、あなたが新しくプログラミング言語を作るならばprivateメンバーのアクセス範囲はどう設計しますか?

オブジェクトに感情移入する人であれば、「自分だけ」と答えるかもしれません。ホモサピエンス同士であっても私物を他人に無遠慮に触られると嫌ですからね。しかし、現実のプログラミング言語を見ると、privateなメンバーは同じクラスであればインスタンスに関わらず参照できるものが多いと思います。

カプセル化は何のためにあるか

そもそもカプセル化は何のためにあるのでしょうか?理由はいくつか挙げられるでしょう。

一つは「型の不変条件を守るため」です。型の不変条件が守られているかプログラマーがチェックする時、メンバーがpublicであればプログラム全体からそのクラスを触る箇所を探してチェックしなければいけません。一方、メンバーがprivateであればチェックする範囲はそのクラスの実装だけで済みます。

別の理由として「変更時の影響範囲を抑える」が考えられます。複数のパッケージを利用する開発の場合、一つのパッケージの一つのクラスの実装の詳細を変えたために他のパッケージが壊れた、ということになると厄介です。「バージョン違いで変わる可能性のある実装の詳細」に触れるのは自分のパッケージのみに制限しておけば、下流のパッケージを壊す心配がなくなります。

いずれにせよ、 カプセル化をする目的はプログラマーがコードを管理しやすくするため です。 決して「オブジェクトに自我があって、その私有物を尊重するから」ではない のです。

そして、この原則に立ち返れば「privateの対象がクラスという単位であること」に深い必然性はなく、「同じモジュールのみから参照可能」「同じパッケージのみから参照可能」という修飾子があっても良いと思えるでしょう(実際、言語によってはそういう修飾子があります。C#のinternalなど)。

オブジェクトに感情移入させるような教材は有害ではないか

「オブジェクトに自我はない」。当たり前ですね。プログラミング言語のオブジェクトなんてメモリ領域とメソッド(振る舞い)の組み合わせでしかないのですから。自我があるのはコードを管理するプログラマーです(AIがコードを管理するようになったらどうするのかという話はここではしません)。

しかし、この「当たり前」を初学者は「当たり前」と思えるのでしょうか?オブジェクト指向の教材では動物クラスや感情移入しやすいクラスを使ったミスリーディングな説明をしていないでしょうか?

というわけで、この記事のタイトルの問題提起なわけです。

(セキュリティーの話題だと複数の主体(攻撃側 vs 防御側)が絡んできますが、それはプログラミング言語の機能とは独立する問題なのでここでは扱いません。)

なお、Rubyでは

この記事の主張に反し、Rubyではprivateを触れるのは「自分のインスタンスだけ」のようです。私よりMatzの方が「オブジェクト指向」というものをよく理解しているに違いないので、きっと私の「オブジェクト指向」の理解が足りないか、あるいはRubyでは自我と羞恥心のある本物の「オブジェクト」を作れるのでしょう。そういうわけで、私の記事の主張は「オブジェクト指向半可通が書いたもの」として話半分で聞いてください。

Discussion

かえるかえる

ご存知でしたら申し訳ありませんが、リンネらによる生物の分類は英語でBiological Classificationと呼びます。これは綱とか門とか目とかそういったものが含まれます。これは英語圏で小学6年生ごろに習います。classは原義が「類」「分ける」の意味で、学校のクラスやクラシックが高級なのもそれ由来です。
そのためclass Animalは、もともと哺乳類(≒ 哺乳綱 / Mammalia)を意識したもので、自然な流れでできたものだと思います。

また数学の集合論にも「類(class)」がありますが、もともとの考え方はこちら由来だと考えています。
対象が動物であっても機械的にその性質を捉えるような理系的感覚で記述しているのかもしれません。

ただし、以上は推測ですので特にソースはありません。

Object(客観 / 対象 / 主観から見たモノ)と考えると主体はなく自我はありませんが、Agentと捉えて自我風味のものを搭載させることはできるので、OOPはその点がおもしろいと思います。もともとOOPはObject同士がメッセージパッシングし合うもので、全体の管理者がすべてを把握していなくても、classで定義した通りにすれば無限に広がりを持つというのが根本思想なのかなと感じています。Switchのブレスオブザワイルドのような感じでしょうか。DogのJohnyとSally、CatのMistyとSnowのような形で「生命を生成できる!」という部分の説明は魅力的な部分だと感じています。
ライフゲームなども、単純なルールの記述で生命らしきものが誕生する!というのが魅力的な部分ですし。

ObjectがObjectを自己参照するときにself となっているのは、まさにObjectに自我があるような思想で書かれたもののように見えます。「自己参照」という言葉自体も自我を示しているような感じがします。自ら己に参じて照らしているので、光り輝くナルシシズムを感じます。
キリスト教圏では「神が人間をプログラムした」という考えが受け入れやすいのもありそうです。「そもそも人間や動物には自我ってなくて、われわれは神の定めた運命の下僕だよね」みたいな思考です。
また、自分はclassに感情を設定して感情移入してもいいと思います。その証拠に、美しいコードは美しく、うっとりするではないですか。objectが勝手に発狂して他のobjectに勝手にデータを渡しに行くとか、羞恥心を覚えて重要な情報を渡さないobjectの存在は非常におもしろいと思います。感情移入は現場では全然即効性のある形で顕現せずアカデミックに寄り過ぎますが、もっとプログラミングは自由であっていいはずだと思います。

とはいえ、当時のプログラミング教育と現在のプログラミング教育は在り方から異なる上、日本語圏と英語圏では全然考え方は違うので、アップデートは施されなければならないと思います。
自分も以前はAnimalでの説明は有害だと考えていました。急に何の説明もなくDogやCatと言われても「それって何のつながりがあるの…」と思いますし、その後のコーディングと直結しないので関連性がわからずイライラすると思います。「classってなんだよ」とすら思います。
プログラミングによる生命創造について熱く語れない人がAnimalを例に使うのは単なる前例踏襲主義なので、class Carとかclass Engineとかにした方がいいというふうに思っています。もしくは最初にゲーム作りから始めるとDogやCatはすごく自然なもののように見えます。

それにしてもinterface Animalは凄まじく嫌悪感を感じますね。間違ってないとしてもセンスが悪く、自分は好きではないです。

だめぽだめぽ

オブジェクト指向に陶酔しているところ申し訳ありませんが、この記事にはタイトルと最初の段落以外にも内容があり、特にカプセル化について論じています。長文のコメントを残す暇があったらせめてカプセル化の「カ」の字くらいは言及していただきたいものです。

オブジェクト指向があなたのように文章を読まない人を生み出すのであれば、オブジェクト指向という考え方は人の目を曇らせる麻薬のようなものであり、有害であると判断しなければなりません。