Rubyは比較的読みやすく書きやすい言語ですが、少し踏み入ったところでは独特の設計も少なくありません。今回扱う「特異クラス・特異メソッド」もそのひとつで、はじめて出会うと面食らう概念です。しかし考え方を知るとRubyのオブジェクト指向設計への理解が深まる部分でもあるので、今回の記事では特異クラス・特異メソッドを紹介するとともに、いくつかの方面から解説を加えて行きます。

特異メソッド

説明を簡単にするため、先に特異メソッドを取り上げます。特異メソッドの定義・使い方自体は単純なもので、以下のように書きます。

メソッド定義時に、特定のオブジェクト(例ではHogeクラスのインスタンスである"h"が該当します)にドットをつなげる形でメソッド名を記述しています。こうすることで、他のHogeクラスインスタンスには存在しないメソッドを"h"で独自に定義することが出来ます。

特異クラス

さて、上の特異メソッドもスコープが特定のオブジェクトに限られているだけで、メソッドであることには変わりありません。

一方、Rubyの他の部分では「メソッドはクラスに紐づく」設計になっています。つまり、メソッドはクラスに定義され、クラスをnewしてできるインスタンスたちはメソッドを共有するという設計です。

「メソッドはクラスに紐づく」というRubyオブジェクト指向の基本原則を、特異メソッドというイレギュラーな存在と両立させるには、「すべてのオブジェクトは自分だけの隠しクラスを持つ*1」という仮定を追加してやることです。 そうすれば、特異メソッドは「自分だけのクラスに定義されたメソッド」と考えることができて(一応)筋が通ります*2

この「自分だけのクラス」が特異クラスで、singleton_classメソッドで参照することが出来ます。

単にObjectをnewしただけのインスタンスでも #<Class:#<Object:0x007fea6187f318>> という特異クラスを持っていることがわかります。 なおnilやfalseなどに対して singleton_class を呼んでも、通常のclass呼び出しと同じく NilClassFalseClass が返るだけになります。

ちなみに、当初は正式な英語名が与えられていなかったことから"eigenclass"や"metaclass"などと呼ばれることもありますが、現在はコアライブラリのメソッド名になったこともあり"singleton class"でほぼ固まってきているようです。詳しい歴史的経緯については以下のStackOverFlowが参考になります。

In Ruby, are the terms "metaclass", "eigenclass", and "singleton class" completely synonymous and fungible? - Stack Overflow

次のページでは、特異クラスをオープンする方法、クラスメソッドとの関連を解説します。

  • *1 singleton_class メソッドのドキュメントに "Returns the singleton class of obj. This method creates a new singleton class if obj does not have it." とあることから、オブジェクトが生成された時点で特異クラスを持つようになるわけではなく、必要とされた時に作られるようです。
  • *2 Rubyの設計時にこのような議論があったわけではなく、考え方の一例です。