インスタンスとオブジェクトはどう違うか

プログラミングコラム連載第二回。連載していたと、私も今知った。
コラムと銘打っているので正しいことが書いてある可能性は限りなく低いです。FLT_EPSILON くらい低い。ということで、信じないでください。ただし、実務でオブジェクト指向してるひとの実感ではある。


さて、「インスタンス」という言葉と「オブジェクト」という言葉の違いが分からないという話を良く聞く。そこから初めて、オブジェクト指向のいろいろを騙ろうという企画。
確かに、C++で「string型のオブジェクト」と「stringのインスタンス」が同じものを指していれば、違いが分からないのは当然だよね。まずは直訳してみよう。

ということを前提に、C++Smalltalkの場合を比べてみたい。C++

string("hello")

と書いて生成されるのが、hello という文字列を表すオブジェクト。このオブジェクトは同時に string という名前のクラスのインスタンスと呼ぶ。
Smalltalkでは、文字列リテラル自体がStringクラスのインスタンスになるので、

'hello'

という感じ。これで生成されるのは、同じく、hello という文字列を表すオブジェクトで、Stringクラスのインスタンス

ここまでは同じなんだけど、Smalltalkがちょっと違うのはここから。C++のstringはクラスであって、オブジェクトではない。intなどのクラスではない型と同じような扱いということ。
一方、SmalltalkではStringクラスもオブジェクトだ。この仕組みに明るくない方は、えっ? と思われるかもしれない。クラスとは、クラス変数 (=静的データメンバ) やクラスメソッド (=静的メンバ関数) を、そのクラスのインスタンス変数 (=データメンバ) やメソッド (=メンバ関数) とした、グローバルに生成されたオブジェクトなのだ。Stringクラスに纏わるさまざまな処理がまとめられたもの考えても構わない…かもしれない。
クラスもオブジェクトということは、そのクラス、つまり、クラスのクラスもあるということ。これを「メタクラス」と呼ぶ。'hello'のクラスはString。Stringのクラスは、Stringメタクラス (String class という名前がつく) ということ。
メタクラスもやはりクラスなので、オブジェクトだ。メタクラスもオブジェクトなので、メタクラスにもクラスが存在する。メタクラスのクラスは Metaclass という名前だ。Metaclass クラスもオブジェクトなので……という関係がどこまでも無限に続いている。

と、ここまで言うと、C++的 (=Java的=C#的=内部を気にしないRuby/Python的) なオブジェクト指向に慣れていらっしゃる方々は余計混乱するかもしれない。鶏が先か、卵が先か? と。
これは、「まずクラスがあって、それを元にインスタンスが作られる」という文化に慣れているためだ。「クラス=型」という概念が原因になっている。
教科書的な言い方では、「オブジェクト "hello" はクラス string のインスタンスだ」というのは「オブジェクト "hello" はクラス string に属している」と言い替えられる (実務では聞いたことが無いが)。そもそも、クラスとは日本語で「種別」というような意味だ。
概念的には、「同じ機能を持つモノ (=オブジェクト) は同じ種類 (=クラス) だ」と言える。
実装的には、「同じ機能を持つオブジェクトの処理もまとめて行うのがクラスだ」となる。
つまりは、「まず string というクラスがあって、そこから "hello" というオブジェクトが生成される」よりは、「まず、String というオブジェクトと 'hello' というオブジェクトがあって、その関係性として『'hello' は String に属する』と決める」とでも言ってしまった方が良い。
実装的にはメモリイメージを知るためにはクラスの定義が…とも言えるが、C++な方はこう考えてはいかがだろう?

  • Stringクラスとはそれぞれのオブジェクトの仮想関数テーブルのこと
  • 文字列のメモリイメージと仮想関数テーブルへのポインタをまとめて1つのオブジェクトにする='hello' を String に属させる


ここまでくると、インスタンスとオブジェクトでは、概念の種類が違うということが分かっていただけるかと思う。

インスタンスである」というのはオブジェクトなどに対する形容だというわけ。


オブジェクトなど…と言ったのには理由があって、C++に簡単な「オブジェクトとは関係ないインスタンス」が存在するからだ。その名は「テンプレート」。

template <typename T>
    AClassTemplate;
AClassTemplate<int> an_object;

ここでは、AClassTemplate という名前のクラステンプレートを作成し、テンプレート引数 T=int としてオブジェクト an_object を作成している。ここで、

と呼ばれる。クラステンプレートは のように、実際の型などを指定して初めて一人前のクラスになるが、これを「テンプレートのインスタンス化」とか「インスタンシエイト」(instantiate) と呼ぶ。テンプレートの実例なのだから、正しい命名だ。


公理的集合論との対応を考えれば簡単だ。

  • オブジェクト=元
  • クラス=(部分)集合
  • オブジェクト a はクラス b のインスタンス= a∈b
  • クラス b はクラス c の派生クラス=クラス c はクラス b の基底クラス= b⊂c

公理的と言ったのはSmalltalkの「クラス=オブジェクト」が公理的集合論の「集合=元」と対応するのが面白いとおもったから。


途中で触れたが、次回のテーマは「そもそもオブジェクトとはなんぞや」。
この記事はただのたわごとです。私の直感以外、なんの根拠も有りません。信じたために不利益を被っても責任はおいかねます。