結構前に目にしてはいたものの、ずっとスルーしていましたが、いい加減まずい気がしたので、調べているところです。
メタクラス
Wikipediaより(日本語です)。
メタクラス (metaclass) とは、クラス-インスタンス関係を持つオブジェクト指向プログラミング言語で、クラス自身も「クラスオブジェクト」として扱われる場合にそのクラスオブジェクトが所属するクラスのことをいう。
メタクラス - Wikipedia
さっぱり、意味が分かりません。文の意味は分かるものの、それが何のためにあるのか、イメージ(実感)できません。
とある実装から(Ruby)
実は、以下のソースを眺めていたのがきっかけで、今回の話題になったわけです。
lib/object.rb at master from github's hubahuba — GitHub
class Object def metaclass() class << self; self end end def meta_eval(&blk) metaclass.instance_eval(&blk) end def meta_def(name, &blk) meta_eval { define_method(name, &blk) } end end
メタクラスに関する実装と思わしき部分を抜粋しました。
001:>> class Object 002:1> def metaclass() class << self; self end end 003:1> def meta_eval(&blk) metaclass.instance_eval(&blk) end 004:1> def meta_def(name, &blk) 005:2> meta_eval { define_method(name, &blk) } 006:2> end 007:1> end => nil 008:>> s = "hoge" => "hoge" 009:>> s.meta_def(:to_ss) { return "ss" } => #<Proc:0x0033e8ac@(irb):9> 010:>> s.to_ss => "ss"
普通に、特異メソッドが追加された程度の印象です。
Ruby自体にメタクラスの概念が存在する
Rubyには、メタクラスという概念があり、すべてのクラスは、同名のメタクラスというものを持っていて、これは、Classクラスのインスタンスになっています。
6.5 クラスメソッドはありますか|FAQ::クラス、モジュール - Rubyリファレンスマニュアル
Rubyを使い始めて半年くらいたちますが、「Rubyではこうなんだ」で覚えた事の中に、メタクラスの概念が自然と入り込んでいたようです。Rubyで特異メソッドおよび特異クラスを実現するために、メタクラスという概念が必要だったという事でしょうか。
「すべてがオブジェクト」という思想を持つプログラミング言語(処理系?)を実装するためには、メタクラスという概念を導入(実装)する必要があり、それを具体的な言葉にすると、「クラスはClassクラスのインスタンスである」となる、のでしょうか。
メタクラスの使いどころ
やっぱり、さっぱり、分かりません。
特異メソッドだけに限って考えるなら、「任意のオブジェクトに対し、動的にメソッドを追加したい」ケースは経験しているので、イメージしやすいです。
ベースとなるクラスがあり、そのインスタンスを利用して、要求を満たす操作が可能なオブジェクトにカスタマイズする、といった場合に、特異メソッドを使います。
ActiveRecord のモデルを動的に作る
もしかしたら、これはメタクラスの概念を利用した実装方法になるのでしょうか。
Rails の ActiveRecord で、動的に作成されるテーブルのモデルオブジェクトを作成する場合、あらかじめモデルクラスを定義する事はできません。テーブルが存在しないために、エラーとなります。
そこで、必要になったときにクラスオブジェクトを作るという方針をとります。
001:>> table_name = 'samples' => "samples" 002:>> ActiveRecord::Base.connection.create_table(table_name, :force => true) do |t| 003:>> t.column :value, :string 004:1> end => [] 005:>> model = Class.new(ActiveRecord::Base) do |klass| 006:>> def self.to_s 007:2> table_name.singularize.camelize 008:2> end 009:1> set_table_name table_name 010:1> reset_column_information 011:1> end => Sample(id: integer, value: string) 012:>> silence_warnings do 013:>> Object.const_set(model.to_s, model) 014:1> end => Sample(id: integer, value: string) 015:>> model.create(:value => 'test') => #<Sample id: 1, value: "test"> 016:>> model.find(:all) => [#<Sample id: 1, value: "test">] 017:>> Sample.create(:value => 'hoge') => #<Sample id: 2, value: "hoge"> 018:>> Sample.find(:all) => [#<Sample id: 1, value: "test">, #<Sample id: 2, value: "hoge">]
これは、Rails どころか、Ruby 自体(今より更に)よく理解していない頃に教わりました。上記コードは、今の理解を元に書き起こしたものなので、おかしな事をしているかもしれません。
ただ、やはり、これも、「テーブルを動的に作る場合の ActiveRecord の使い方」と捉えてしまって、メタクラスを使ったテクニックといった話に繋ぐ事ができません。というか、そもそも、メタクラスが関係してくるのかも微妙にわかりません。
Class.new を使って新しいクラスオブジェクトを作り出しているだけです。ただ、「動的にクラスを作れているのは、メタクラスによってクラスがオブジェクトとして扱えるからだ」と考えて、メタクラスに関係しそうだと考えました。
続く
もっと、根本的な話をどこかで見つけて、勉強したいと思っています。
結局、今回はよくわからないまま終わります。正直、本当に何も分からないので、ちゃんとした文献をあたって、根本を知る時間を取らないと駄目だと思っています。続きを書けるか分かりませんが、ある程度の理解を得られるところまでは持っていく予定です。
以上、ギブアップだす。

