【ITニュース解説】In Ruby, Objects Don't Have Methods. How Method Lookup Actually Works.
2026年10月21日に「Dev.to」が公開したITニュース「In Ruby, Objects Don't Have Methods. How Method Lookup Actually Works.」について初心者にもわかりやすく解説しています。
ITニュース概要
Rubyではオブジェクト自身はメソッドを持たず、状態とクラスへのポインタを持つ。メソッドはクラスに格納され、呼び出し時にRubyはクラスを辿りメソッドを検索する。特定のオブジェクト専用の特異メソッドやクラスメソッドは、動的に作られる特異クラスに格納される。メソッド探索は特異クラスから始まる。Tagged Pointerにより数値もオブジェクトとして高速処理される。
ITニュース解説
Rubyでは「すべてがオブジェクト」という考え方が広く知られているが、実はオブジェクトとメソッドの間に一般的なイメージとは異なる重要な仕組みが存在する。多くのプログラマーは、オブジェクトがデータとメソッドをひとまとめにしたものだと考えるが、Rubyのオブジェクトは驚くことにメソッドを一切持たない。
では、メソッドはどこに存在するのだろうか。Rubyのオブジェクトが内部に持つのは、@nameや@emailといったインスタンス変数というデータと、そのオブジェクトが属するクラスを示す「klass」と呼ばれるポインタだけである。メソッドの実体は、オブジェクトではなく、それを生成した「クラス」の中にのみ存在する。クラスは「m_tbl」というハッシュテーブルのような構造でメソッドを管理し、どのメソッド名がどのような処理を行うかという情報を保持している。例えば、user.greetとメソッドを呼び出すとき、Rubyはまずuserオブジェクトのklassポインタをたどり、その指し示すUserクラスのm_tblを検索してgreetメソッドを見つけ出し、実行する。この仕組みにより、多数のオブジェクトが生成されても、すべてのオブジェクトが共通のメソッドをクラスを通して効率的に共有できるため、メモリ使用量が抑えられる。
しかし、Rubyには特定のオブジェクトにだけメソッドを追加できる「シングルトンメソッド」というユニークな機能がある。例えば、ある特定の文字列オブジェクトにだけ、他の文字列にはない独自のshoutメソッドを定義できる。これはオブジェクトがメソッドを持たないという原則と矛盾するように見えるが、この謎を解くのが「特異クラス(eigenclassまたはsingleton class)」と呼ばれる、Rubyが動的に生成する隠れたクラスである。特定のオブジェクトにシングルトンメソッドが定義されると、Rubyはそのオブジェクト専用の匿名な特異クラスをその場で作成し、オブジェクトのklassポインタをこの新しい特異クラスに付け替える。そして、定義されたシングルトンメソッドは特異クラスのメソッドテーブルに格納される。この特異クラスの親(スーパークラス)は、もともとのオブジェクトのクラスになるため、メソッド探索時には特異クラスから始まり、そこにメソッドが見つからなければ元のクラスへと探索が続くことで、個別のオブジェクトにだけ適用される特別なメソッドが実現されるのだ。
この特異クラスの理解は、「クラスメソッド」という概念を正しく理解する上でも非常に重要となる。Rubyにおいてdef self.recentのように定義される「クラスメソッド」は、JavaやC++のような静的メソッドとは根本的に異なる。Rubyのクラス自身もまた「Class」クラスのインスタンスであり、一つのオブジェクトとして扱われる。したがって、Post.recentのようなクラスメソッドの定義は、特定のオブジェクトにシングルトンメソッドを定義するのと全く同じ原理で動作する。つまり、「クラスメソッド」と呼ばれるものは、実際にはクラスオブジェクト(この例ではPost)の特異クラスに定義されたシングルトンメソッドに過ぎない。Rubyには厳密にはインスタンスメソッドしかなく、「クラスメソッド」という呼び方は、クラスオブジェクトの特異クラスに属するインスタンスメソッドを指している。
メソッドが呼び出された際、Rubyは「祖先チェイン」と呼ばれる厳密な順序でメソッドを探索する。最初に見つかったメソッドが実行される。探索は、まずメソッドを呼び出されたレシーバの特異クラスから始まり、特異クラスにprependされたモジュールがあれば、そのメソッドが優先される。次に、レシーバの本来のクラス、そしてそのクラスにprependされたモジュール、さらにincludeされたモジュールが順に探索される。その後、クラスの親であるスーパークラスへとさかのぼり、同様にそのスーパークラスにprependされたモジュール、クラス自身のメソッド、includeされたモジュールが確認される。最終的には、ほぼすべてのRubyオブジェクトの共通の祖先であるObject、Kernel、BasicObjectクラスまで探索が行われる。
もし、この祖先チェインを最後までたどってもメソッドが見つからなかった場合、Rubyはすぐにエラーを出すのではなく、再度最初から「method_missing」というメソッドを探し始める。Kernelモジュールが提供するデフォルトのmethod_missingはNoMethodErrorを発生させるが、独自のmethod_missingを定義することで、未定義のメソッド呼び出しを捕捉し、柔軟な処理を実現できる。これは、Rubyの強力なメタプログラミングを支える重要な仕組みである。
Rubyでは数値や真偽値などもすべてオブジェクトでありメソッドを持つ。しかし、1 + 1のような基本的な計算のたびにオブジェクトを生成するとパフォーマンスが低下する。CRubyでは「タグ付きポインタ」という最適化技術を用いる。これは、小さな整数や真偽値、nilなどの特定の値を、通常のヒープメモリにオブジェクトとして割り当てる代わりに、ポインタ自身に直接埋め込んで表現する仕組みだ。例えば、小さな整数はポインタの下位ビットに特定のパターンを付加して示される。これにより、Rubyが数値オブジェクトのメソッドを呼び出す際でも、ヒープメモリへのアクセスやガベージコレクションのオーバーヘッドなしに、高速な処理が可能となる。「すべてがオブジェクト」という概念的な一貫性を保ちつつ、実用的なパフォーマンスを実現しているのだ。