Closed kazuminn closed 3 years ago
- 単純なRubyの値の具体的な境界線
Fixnumの場合ruby.hでFIXNUM_MAX
で境界線が定義されてます。
VALUEポインタの中に直接保存するオブジェクトのことをRHGではVALUE埋め込みオブジェクトと呼んだりもしています。
Fixnumの他にもtrue/false/nil、あとRuby2.0ではFloatもVALUEに埋め込まれてます。 http://www.atdot.net/~ko1/diary/201212.html#d11
境界線はVALUEのサイズからフラグ分を抜いて収まるか収まらないかです。 VALUEのサイズは環境によって違います。
2、すべてがオブジェクトです
p [0, 0.0, :symbol].all? {|x| x.is_a?(Object) } # => true
例えば、instance_variablesメソッドを呼び出して(2.0以降では、int ,floatがこのメソッドがない。また、2.1以降も、symbolで呼び出せない。)
呼び出せます。
puts RUBY_VERSION
p [0.class, 0.instance_variables]
p [0.0.class, 0.0.instance_variables]
p [:symbol.class, :symbol.instance_variables]
# 2.2.2
# [Fixnum, []]
# [Float, []]
# [Symbol, []]
1つ目の質問は、納得しました。
2つ目の質問に関して。
is_a?メソッドは、の戻り値がTrueだからってオブジェクトなのか疑問。
is_a?のメソッド本体を読んでみると(読み間違えてるかもしれないです。) VALUE埋め込みオブジェクトにあるフラグとancestorメソッドで
irb(main):004:0> Fixnum.ancestors => [Fixnum, Integer, Numeric, Comparable, Object, Kernel, BasicObject]
クラスの継承を巡って一緒のkcallがあれば、True。
これで、本当に
すべてがオブジェクトです
と言えるのか。
2つ目の質問はよく意図が分からなかったんですよねー。
Rubyでは全ての値がオブジェクトで、Objectクラスのインスタンスです。
なので実装上VALUE埋め込みオブジェクトな1とかnil
とかtrue
/false
みたいな値に対してもメソッドを呼び出せます。
なぜオブジェクトではない思うんですか?(1とか2に対してinstance_variable_set
とかが呼び出せないからですか?)
なぜオブジェクトではない思うんですか?
Rubyのオブジェクトの定義は、klassのようにclassを示すものとインスタンス変数の配列を持っている。
でも、「VALUE埋め込みオブジェクトは、インスタンス変数の配列を持っていない」のでオブジェクトではないと思いました。
今、オブジェクト指向における「オブジェクト」とRubyにおける「オブジェクト」の2つが混ざってて、混乱している感じに見えます。
オブジェクト指向的な視点から見れば「クラスから生成された実態」のことをオブジェクトと呼んでいるので、Rubyにおける数値やシンボルその他諸々は全てObjectクラスのインスタンスでありますから「すべてがオブジェクト」と言われていると思います。
一方、Rubyの視点からみれば「オブジェクトはクラスへのポインタとインスタンス変数の配列を持っている」と書籍では定義されています。ここで「数値やSymbolはインスタンス変数の配列を持っていないからオブジェクトではないのでは」と疑問が生じる訳ですが、書籍には「2.0以降は数値、2.1以降はSymbolオブジェクトがそれぞれfreezeされ 〜 インスタンス変数を持てなくなっている。」とあります。これは調べたところ原著にはなかったので、新しく追加された記述だとは思うのですが、正確には「オブジェクトがfreezeされ内部の値の変更が出来なくなったため、インスタンス変数の追加が出来なくなった」だと思います。(実際1.9.3だと出来ますしね)
なのでオブジェクト自身はinstance_variable_setのメソッド自体は持ってるけど、実行は出来ない状態なのです。
[2] pry(main)> 3.respond_to?(:instance_variable_set)
=> true
[3] pry(main)> 3.instance_variable_set("@val", "3")
RuntimeError: can't modify frozen Fixnum
from (pry):3:in `instance_variable_set'
じゃあじゃあ。インスタンス変数の配列、いわゆるivptrの値は数値(Float, Fixnum)やSymbolオブジェクトにおいてどう扱われているの?って話なんですよね。(一応instance_variablesの返り値が空の配列なので、どこかに参照をもっているか、空の配列を直接決め打ちで返しているかのどっちかなんでしょうね。このあたりはソースを読んで調べるしかなさそうです)
個人的な感想ですが、この辺りをワイワイ議論するのは楽しそうです!
Rubyのオブジェクトの定義は、klassのようにclassを示すものとインスタンス変数の配列を持っている。 でも、「VALUE埋め込みオブジェクトは、インスタンス変数の配列を持っていない」のでオブジェクトではないと思いました。
https://github.com/ie-developers/ie-questions/issues/23#issuecomment-117605262 で書いたようにinstance_variables
を呼び出せばインスタンス変数の配列を持っていることを確認できます(空ですが)。
1とか2に対してinstance_variable_setとかが呼び出せないからですか?
と書きましたが @siman-man さんの書いてるコメントが正確そう。
正確には「オブジェクトがfreezeされ内部の値の変更が出来なくなったため、インスタンス変数の追加が出来なくなった」
普通のオブジェクトでもfreezeするとインスタンス変数を変更することはできません。
class C
end
c = C.new
c.freeze
c.respond_to?(:instance_variable_set)
begin
c.instance_variable_set(:@foo, :bar)
rescue => e
puts e.message
end
begin
42.instance_variable_set(:@foo, :bar)
rescue => e
puts e.message
end
# can't modify frozen C
# can't modify frozen Fixnum
このあたりのissueにfreezeされた経緯載ってます。
Feature #3222: Can bignums have singleton class & methods? - Ruby trunk - Ruby Issue Tracking System
Matzのコメントを抜粋すると
Ah, some programs might expect modifying instance variables of fixnums. But I think you can ignore such programs for most of the case. Try it.
言語の内部の実装をどうしているかの話であって、挙動がオブジェクトならオブジェクトと見なしちゃっていいんじゃないかなーと思いました
「Ruby Under a Microscope」読んでいると、わからないところが発生して ググってもわからないので、質問します。
二つあります。
まず一つ目は、
「単純なRubyの値は、構造体を全く必要しない」(p,120引用) つまり、 「小さい数値などは、ある大きさの変数領域を獲得して、整数値+FLAGをstoreする」 とのことです。 ここで疑問が発生しました。 単純なRubyの値の具体的な境界線は、どのなのかなー? 例えば、255以下は、構造体を使用せず、それ以上は、使用するとか。
二つ目
Rubyは、すべてがオブジェクトではないのでは?との疑問が発生しました。 なぜなら、 以上の定義によると、(「小さい数値などは、ある大きさの変数領域を獲得して、整数値+FLAGをstoreする」)小さい数値などは、オブジェクト構造でないから
でも、
この、変数をオブジェクト構造っぽくできる。 例えば、instance_variablesメソッドを呼び出して(2.0以降では、int ,floatがこのメソッドがない。また、2.1以降も、symbolで呼び出せない。)
とかで、オブジェクト構造になる("some arupaka"変数の最後にklassポインタのように、classを指し示すためのFLAGが入っているから)
いや、でも、
短いコードの簡単なStringインスタンスは、オブジェクト構造じゃなくない? 例えば、
とか
なぜなら、 Rubyのオブジェクトの定義は、klassのようにclassを示すものとインスタンス変数の配列を持っている。 のが前提。 この場合、 klassのようなFlagを持っているが、インスタンス変数の配列を持っていない。
つまり、
Rubyは、すべてがオブジェクトとは、言い切りれないのではないでしょうか?