メタクラスってなんなんだすか?(1)

結構前に目にしてはいたものの、ずっとスルーしていましたが、いい加減まずい気がしたので、調べているところです。

メタクラス

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 を使って新しいクラスオブジェクトを作り出しているだけです。ただ、「動的にクラスを作れているのは、メタクラスによってクラスがオブジェクトとして扱えるからだ」と考えて、メタクラスに関係しそうだと考えました。

続く

もっと、根本的な話をどこかで見つけて、勉強したいと思っています。

結局、今回はよくわからないまま終わります。正直、本当に何も分からないので、ちゃんとした文献をあたって、根本を知る時間を取らないと駄目だと思っています。続きを書けるか分かりませんが、ある程度の理解を得られるところまでは持っていく予定です。

以上、ギブアップだす。

プロフィール

このブログ記事について

このページは、koshigoeが2008年9月18日 00:30に書いたブログ記事です。

ひとつ前のブログ記事は「User-Supplied Identifierの復習」です。

次のブログ記事は「PASMO・イン・ジャケット」です。

最近のコンテンツはインデックスページで見られます。過去に書かれたものはアーカイブのページで見られます。