質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.50%
Ruby

Rubyはプログラミング言語のひとつで、オープンソース、オブジェクト指向のプログラミング開発に対応しています。

Q&A

解決済

2回答

953閲覧

ClassクラスとModuleクラスの関係について知りたい

Mugheart

総合スコア2340

Ruby

Rubyはプログラミング言語のひとつで、オープンソース、オブジェクト指向のプログラミング開発に対応しています。

0グッド

0クリップ

投稿2020/01/24 01:34

編集2020/01/24 01:43

知りたいこと

Classクラスが自身のインスタンスであるModuleクラスを継承しているが、
それを実現している仕組みを知りたい。

詳細

RubyにはClassクラスとModuleクラスがあり、継承関係は
Object > Module > Class です。

ですが、Classクラスが継承しているModuleクラスはClassクラスのインスタンスです。
またClassクラス自身もClassクラスのインスタンスです。
ついでにClassの親クラスであるObjectクラスもClassクラスのインスタンスです。
当たり前ではありますが...。

rb

1Class.superclass 2#=> Module 3 4Module.instance_of?(Class) 5#=> true 6 7Class.instance_of?(Class) 8#=> true 9 10Object.instance_of?(Class) 11#=> true

リファレンスには

個々のクラスはそれぞれメタクラスと呼ばれる名前のないクラスをクラスとして持っていて、Class はそのメタクラスのクラスです。

とありますが、利用する上では重要でないとして詳しくは書かれていません。

一応自分で調べるつもりではあり、「Rubyのしくみ」という書籍を購入しましたが、
もしこの辺りのことを既にご存知の方がいましたら事前知識としてアドバイスしていただきたいです。

現在の理解

現在の理解はざっくりとですが以下の通りです。

  • 「クラス」と「クラス名」を分けて考える必要がある
  • 「クラス名」がClassクラスのインスタンスであり、その「クラス」の実態を参照できる
  • この「クラス」にあたるものがメタクラスである

これで正しいのか自信はないです。
また、詳しいことは何もわかっていません。

間違いの指摘や詳しいアドバイスをお持ちしております。
自身で納得のいく理解ができた時点で自己解決とします。
(もちろん完璧な回答があればそれがベストアンサーです。)

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

asm

2020/01/24 03:05

実現している仕組みというとC言語レベルの実装の話(そもそもC言語に継承はない)になって、つまらないものになると思います そうでないというならば、「言語仕様でそう決まっている」というこれまた面白みに欠ける話になります。 そういうのでいいんですかね?
Mugheart

2020/01/24 03:59

> C言語レベルの実装の話(そもそもC言語に継承はない) この辺りの話をやんわりと教えていただけると非常に助かります。 C言語の知識が全くないままRubyを使っているので深いところを調べるといつもC言語がネックになるのです。
guest

回答2

0

本を読むなら読んでから不明点を質問するのでは?

「クラス名」がClassクラスのインスタンスであり、その「クラス」の実態を参照できる

クラス名は、クラスオブジェクトが代入されている定数名です。
(=クラス名はクラスオブジェクトについているラベルです)
クラス内のメソッドからその定数名が参照できるというちょっと特別な物ですが。
クラスオブジェクトに最初に付けられた定数名(ラベル)がクラス名になります。

Ruby

1[1] pry(main)> a=Class.new 2=> #<Class:0x80e5f314> 3[2] pry(main)> a 4=> #<Class:0x80e5f314> 5[3] pry(main)> a.new 6=> #<#<Class:0x80e5f314>:0x80e96ee0> 7[4] pry(main)> a.new.class 8=> #<Class:0x80e5f314> 9[5] pry(main)> A=a 10=> A 11[6] pry(main)> a.new.class 12=> A 13[7] pry(main)> B=a 14=> A 15[8] pry(main)> a.new.class 16=> A

定数に代入しないでも多分クラスオブジェクトは使えると思います。
class a;endはエラーですが。

Ruby

1[9] pry(main)> a.class_eval "def foo;p 123;end" 2=> :foo 3[10] pry(main)> a.new.foo 4123 5=> 123

投稿2020/01/24 03:21

編集2020/01/24 03:22
otn

総合スコア84423

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

Mugheart

2020/01/24 03:56

読んでもなお分からなければ質問するということですよね。 購入前に少し目を通してみたのですが、結構根気強く読まなければいけないような内容でしたので、できれば事前にアドバイスを得てから読んだ方がすんなり理解できるかと思い、自分勝手ではあるんですがそういう意図での質問でした。 Class名に関してはその通りで class Name; end が Name = Class.new の SyntaxSugar という理解です。 言語化が難しいところで質問文中の「クラス名」は概念的な意味合いで書いていました。Classクラスの「Class」はクラス名であってClassクラスの実態を表すものではない...という表現で正しいか分からないんですが...。 ClassインスタンスをAとBという定数に入れた場合のクラス名はAもしくはBとなり、必ずしもAとなるわけではないという理解なのですが、提示されているコードだとAのままなのですかね? ふんわりとした理解で質問してしまっているので本旨が伝わりづらかったと思いますが、最終的には自身のインスタンスを継承するしくみ...というかどういう理屈でそれが可能なのかということを理解したいのです。 修正依頼でasmさんがC言語領域の話になるとおっしゃっているのでC言語の仕様を先にある程度理解する必要があったのかもしれません。
otn

2020/01/24 04:09 編集

> ClassインスタンスをAとBという定数に入れた場合のクラス名はAもしくはBとなり、必ずしもAとなるわけではない それは間違っています。2回目以降の代入ではクラス名には影響しません。 リファレンス: > 名前のないクラスは、最初に名前を求める際に代入されている定数名を検索し、見つかった定数名をクラス名とします。 > 修正依頼でasmさんがC言語領域の話になるとおっしゃっているのでC言語の仕様を先にある程度理解する必要があったのかもしれません。 抽象的なままで理解したいのか、Cによる実装まで理解したいのかによりますね。 抽象的な理解を求めるとすると、リファレンスだと、厳密に書いてないところもあるので、JISの規格書をみるとより厳密にわかるかと思います。規格になって以降の仕様変更分はわかりませんが、このあたりは変わってないと思います。私も規格書はごく一部を見ただけですが。 踏み込んだ点になると、ruby-list メーリングリストで聞いた方が良いかもしれません。
Mugheart

2020/01/24 04:10

> それは間違っています。2回目以降の代入ではクラス名には影響しません。 なるほど、間違いに気づけました。ありがとうございます。 > 抽象的なままで理解したいのか、Cによる実装まで理解したいのかによりますね。 できれば実装まで理解したいですが、すぐには難しいので今の所は抽象的な理解で良いと思っています。
Mugheart

2020/01/24 04:12

直接質問内容とは関係ないですが、 > ClassインスタンスをAとBという定数に入れた場合のクラス名はAもしくはBとなり、必ずしもAとなるわけではない モジュールと混同してしまってたかもしれないです。モジュールはこの理解でよかったですよね...。
otn

2020/01/24 04:19

> モジュールはこの理解でよかったですよね...。 どういうケースのことかよくわかりません。
Mugheart

2020/01/24 04:28 編集

すみません、詳細に書きます。 m = Module.new A = m B = m m.name とした場合にModuleインスタンスの名前がAもしくはBとなるという理解であっているでしょうか? 追記 Classに関しても a.name した時の返値は不定でしたね。 Class名と .name での返値が一致すると思っていたのでそもそもそこが間違いでした。
otn

2020/01/24 04:31

class Foo;include B;end Foo.Ancestors してみましたが、名前はAのようです。やはり最初に代入した物が名前ですね。 もちろん、別名(mやB)でもアクセスできますが。
Mugheart

2020/01/24 04:33

すみません、詳細にありがとうございます。 そもそもの勘違いに気づきました。お恥ずかしい...。
otn

2020/01/24 04:45

a.name が不定とリファレンスに書いてあると言うことで、私が勘違いしている気もしてきました。 > 名前のないクラスは、最初に名前を求める際に代入されている定数名を検索し、見つかった定数名をクラス名とします。 は、「最初に」は「代入」にかかる修飾語だと思っていましたが、 「名前のないクラスは、名前を求める際に代入されている定数名を検索し、最初に見つかった定数名をクラス名とします。 」という意味なのかなぁ。
Mugheart

2020/01/24 05:35 編集

確認してきました。以下引用です。 > 2.6までは名前を求めるときに定数名を探索、2.7からは定数への代入時に決定、です > A に代入した時点で決定するので、そのままです 2.7からはクラス名は最初に定数に代入された時点でその名前に決定され、以後他の定数に代入されたとしても変わることはないそうです。
Mugheart

2020/01/24 05:09

なのでおそらくClass#name(Module#name)に関しても同様なんだと思います。
otn

2020/01/24 05:49

ということは、2.6までは「最初に代入した物」では無かったのですね。 ありがとうございました。
guest

0

自己解決

仕組みを理解できたわけではないんですが、キーとなりそうなメタクラスについてはなんとなくわかってきたので以下の内容で自己解決とします。

クラスとメタクラス

クラスのクラスです。

より正確に言えば、個々のクラスはそれぞれメタクラスと呼ばれる名前のないクラスをクラスとして持っていて、Class はそのメタクラスのクラスです。この関係は少し複雑ですが、Ruby を利用するにあたっては特に重要ではありません。

るりま

メタクラスとは

メタクラスはインスタンスがクラスとなるクラスのことである。

wikipedia

クラスがインスタンスの振る舞いを定義するようにメタクラスはクラス自体の振る舞いを定義する。クラスメソッドを定義するときはこのメタクラスにアクセスし、インスタンスメソッド定義をしている。そして全てのクラスはClassクラスのインスタンスである。

rb

1class A 2 class << self 3 self 4 end 5end 6#=> #<Class:A>

メタクラスはインスタンスがクラスとなるクラスなのでこれがAクラスのメタクラスとなる。

Classクラスがメタクラスなのか

全てのメタクラスはClassクラスだが、それはClassクラスのインスタンスであるClassクラスなのでRubyのClassクラスが全てのクラスのメタクラスなのかと言われるとそうではなく、概念的には全てのクラスそれぞれが対となるメタクラスを持っているということになる(難しい)。

メタクラスでないClassクラスのパターン

rb

1class A; end 2class << A.new 3 self 4end 5#=> #<Class:#<A:0x00007fd2870f1458>>

これはClassクラスであるが、このクラスのインスタンスがクラスではないのでこのClassはメタクラスではない。これは固有クラスとか匿名クラスとか呼ばれるものらしい。

rb

1class Foo 2 self 3end 4#=> Foo

ClassクラスのインスタンスであるFooクラス。FooクラスのインスタンスはクラスではないのでFooクラスはメタクラスではない。またFooクラスのクラスであるClassクラスはインスタンスがFooクラスでクラスなのでメタクラスなのかとなるが、おそらくそれは違う。概念的にはそれぞれのクラスとそのメタクラスは1:1の関係のはずである。

メタクラスはインスタンスがクラスとなるクラスのこと。

おそらくRubyにおいて正しくは「メタクラスはインスタンスがクラスとなる特異クラスのこと。」
この仮定が正しければFoo = Class.newClassFooのメタクラスではない。

メタクラスは全てClassクラスのオブジェクト

メタクラスは全てClassクラスのオブジェクトである。特異クラス自体が全てClassクラスのオブジェクトなので当然ではある。

class Class def self.foo 'Hello' end def bar "World" end end BasicObject.foo #=> "Hello" BasicObject.bar #=> "World"

メタクラスは(Classクラスも含めた)それぞれのクラスの設計書となるが、Classクラスはそのメタクラスの設計書になるので、Classクラスのインスタンスメソッドとクラスメソッドは(メタクラスも含めた)全てのクラスのクラスメソッドとなる。


なんとなくこんな理解です。
この辺りのプロがいましたら指摘や補足をしていただけるとありがたいです。

投稿2020/02/21 08:02

Mugheart

総合スコア2340

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.50%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問