世界線航跡蔵

Mad web programmerのYuguiが技術ネタや日々のあれこれをお送りします。

2008年12月14日

Rubyのメタクラス階層について再び

承前

3ヶ月ばかり時間が空いてしまったけれども、sumimさんの記事に答えたいと思います。

yugui さんの図は、たしかにクラスと特異クラス(メタクラス)が揃って並んでいて見た目にはきれいなのですが、これだとクラスが整然と並んでこそいるものの、肝心のメタ階層がどうなっているかという情報のほうは、正直なところ、いささか得にくいものになってしまっています。

いいえ、これで良いのです。なぜって?

これが私の図(下記再掲)で一番言いたかったことで、ただ、一般のメタクラスと#<Class:Class>を並べているのはいただけないかな。これはsumimさんのSmalltalk版の図を意識しすぎて、まずかったかなと思います。

図1:

20080914-metaclass-hierarchy1.png

うん、やっぱり

メタ階層がどうなっているかという情報のほうは、正直なところ、いささか得にくいものになってしまっています。

これは当たってるかもしれません。

図の修正

ただ、私としてはとにかくsumimさんの図でClassが#<Class:Class>よりも一般のメタクラスに近いのは納得がいかなくててですな。

反省を活かして一般のメタクラスから#<Class:Class>を浮かせるとこうなりました。

図2:

20081214-metahierarchy-pre01.png

さて、こうしてみると#<Class:BasicObject>と#<Class:Object>が不自然に頑張ってClassのインスタンスになっていることが分かります。#<Class:Yapoo>は#<Class:Object>のサブクラスなのに、どうして両者にこんなに大きな違いがあるんでしょう?

こうしてみたらどうでしょうか? (図3)

20081214-metahierarchy-pre02.png

たぶん、これがRubyにとっての正解です。図3のようになっていなかったのは何故かというと、単に実装の都合だったりします。図2ほうがクラス階層をブートする部分のコードが何行か短くて済むから。あとから図3のように直すには何行かコードを足さなければならなかったから。そして、誰も文句を言わなかったから。

と言うわけで、実はRuby 1.9のメタクラス階層は私が図3のように直してしまったのでした。

クラスはメタクラスのインスタンス。メタクラスは#<Class:Class>のインスタンス。メタクラスと#<Class:Class>は等しくClassを通じてObjectを継承する。こうしてすべてがObjectになる。どうでしょうか?

そして、クラス、メタクラス、メタメタクラスと辿る上でSmalltalkのMetaclassに近いのは、たぶんだけれども、Classではなくて#<Class:Class>のほう*1。 sumimさんが、Smalltalk → Rubyにおける対応関係を

  • Metaclass → Class
  • Metaclass class → #<Class:Class>

と仮定したのは、恐らくは私が直す以前の階層初期化のサボりに加えて、ClassはClassという名前で呼ばれるユーザーに身近なものであるのに対して#<Class:Class>はClassのクラスとしてのみ定義される名前のない何かであるからではないかと推察します。これを、Metaclass classがMetaclassのメタクラスであるがゆえにMetaclass classという名前なのと同じように見立てたのでは?

メタクラスはクラスか

オブジェクトがクラスに属するように、クラスが属する何か。それをメタクラスと呼ぶとすればメタクラスはクラスでしょうか?

Smalltalkではそうではないです。(GNU Smalltalk)

Object subclass: #Foo
Foo isKindOf: Class             "true"
Foo class isKindOf: Class       "false"

一方、メタクラスのクラスであるMetaclassはクラスです。

Foo class class                     "Metaclass"
Foo class class isKindOf: Class     "true"

MetaclassのメタクラスであるMetaclass classは再びクラスではありません。クラスではなくてメタクラスですから。

Foo class class class                 "Metaclass class"
Foo class class class isKindOf Class  "false"

すると、

  • Metaclass → Class
  • Metaclass class → #<Class:Class>

というSmalltalk → Ruby対応関係は自然に見えてきますね。Classは日の当たるところにいるクラスであるのに対して、#<Class:Class>は特異クラスという特殊な存在ですから。

でも、これはRuby流のメタクラス狂の感覚からすると転倒している、というのが私の言いたかったことなのでした。にもかかわらず、sumimさんの図に合わせることにこだわって本題からずれてしまったのは、私こそ「図が悪い」なのだったのだと思いますです。

何故Rubyは転倒しているか

逆に見ればRubyが転倒しているのです。クラスのクラスのクラスであってクラスである#<Class:Class>をClassと呼ぶのではなく、なぜ#<Class:Class>の祖先であるというに過ぎないClassが表舞台にいるのでしょうか。そして、#<Class:Class>が、マニア以外は気づかないような場所に追いやられているでしょうか。

これはRubyの無限退行モデルと呼ばれるメタクラス階層編成によるものです。無限退行モデルのためにすべてのクラスのクラスが#<Class:Class>であるかというとそうではなくて、クラスや、メタクラスや、それらを束ねる究極の何かはClassになります。

図4

20081214-metahierarchy-ideal.png

このように、Rubyでは、クラスがあって、クラスのクラス(メタクラス)があって、メタクラスのクラス(メタメタクラス)があって、と果てしなく続いていきます。

次の記事で、無限退行モデルについてもう少し詳しく見てみたいと思います。

概要

簡単に概要だけ先に述べておくと、無限退行モデルを取っている理由はクラスを普通のオブジェクトであるようにするためです。

Ruby式にクラスに属する何かをオブジェクトと呼びましょう。そうすると、Smalltalkにおけるクラスはオブジェクトではありません。なぜならば、クラスはメタクラスに属するのであって、メタクラスはクラス(isKindOf: Class)ではないからです。クラスはクラスには属しません。

メタクラスもまたクラスに属するようにして、かつ整合性を取るためためにRubyは無限退行モデルをとっています。

ちなみに、この言い方には不公正があります。むしろ源流であるSmalltalkからいえば、オブジェクトよりも先にクラスが立つRubyが邪道なのです。isKindOf: Objectであるという意味で言えば一般のオブジェクトもクラスもメタクラスも等しくオブジェクトです。


*1 初めは「SmalltalkのMetaclass classに近いのは、たぶんだけれども、#<Class:Class>ではなくてClassのほう」と書いていた。指摘により修正。


トラックバック

http://yugui.jp/articles/803/ping
[OOPL] Ruby1.9 のクラスのメタ階層を整理する 4 (sumim’s smalltalking-tos)
Rubyのメタクラス階層について再び @ 2008年12月 @ ratio - rational - irrational @ IDM ぜんぜん関係ない話ですが、この記事で Yugui さんが、ふつうに Smalltalk を使って確かめた結果を例として挙げてくださっているのが個人的にはとっても嬉しかったです。 とかく世間

コメント

umejava (2008年12月15日 14時21分13秒)
<p>Smalltalkの場合、ClassとMetaclassの抽象クラスとして、ClassDescriptionがありますので、それがいわゆる(クラスとメタクラスをまとめた)「クラス的なもの」ということになります。<br />Foo class isKindOf: ClassDescription &quot;true&quot;ということですね。</p>
blog comments powered by Disqus

ご案内

前の記事
次の記事

タグ一覧

過去ログ

  1. 2016年07月
  2. 2016年01月
  3. 2015年09月
  4. 2015年08月
  5. 過去ログ一覧

フィード

フィードとは

その他

Powered by "rhianolethe" the blog system