ie-developers / ie-questions

public questions for ie students.
10 stars 0 forks source link

RStringと小さい数値 #23

Closed kazuminn closed 3 years ago

kazuminn commented 9 years ago

「Ruby Under a Microscope」読んでいると、わからないところが発生して ググってもわからないので、質問します。

二つあります。

まず一つ目は、

「単純なRubyの値は、構造体を全く必要しない」(p,120引用) つまり、 「小さい数値などは、ある大きさの変数領域を獲得して、整数値+FLAGをstoreする」 とのことです。 ここで疑問が発生しました。 単純なRubyの値の具体的な境界線は、どのなのかなー? 例えば、255以下は、構造体を使用せず、それ以上は、使用するとか。

二つ目

Rubyは、すべてがオブジェクトではないのでは?との疑問が発生しました。 なぜなら、 以上の定義によると、(「小さい数値などは、ある大きさの変数領域を獲得して、整数値+FLAGをstoreする」)小さい数値などは、オブジェクト構造でないから

でも、

この、変数をオブジェクト構造っぽくできる。 例えば、instance_variablesメソッドを呼び出して(2.0以降では、int ,floatがこのメソッドがない。また、2.1以降も、symbolで呼び出せない。)

irb(main):001:0> str = "some arupaka"
=> "some arupaka"
irb(main):002:0> str.instance_variables
=> []
irb(main):003:0> str.instance_variable_set("@va","value")
=> "value"

とかで、オブジェクト構造になる("some arupaka"変数の最後にklassポインタのように、classを指し示すためのFLAGが入っているから)

いや、でも、

短いコードの簡単なStringインスタンスは、オブジェクト構造じゃなくない? 例えば、

arupakas= "some arupaka"

とか

なぜなら、 Rubyのオブジェクトの定義は、klassのようにclassを示すものとインスタンス変数の配列を持っている。 のが前提。 この場合、 klassのようなFlagを持っているが、インスタンス変数の配列を持っていない。

つまり、

Rubyは、すべてがオブジェクトとは、言い切りれないのではないでしょうか?

hanachin commented 9 years ago
  1. 単純な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のサイズは環境によって違います。

hanachin commented 9 years ago

2、すべてがオブジェクトです

p [0, 0.0, :symbol].all? {|x| x.is_a?(Object)  } # => true
hanachin commented 9 years ago

例えば、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, []]
kazuminn commented 9 years ago

1つ目の質問は、納得しました。

2つ目の質問に関して。

is_a?メソッドは、の戻り値がTrueだからってオブジェクトなのか疑問。

is_a?のメソッド本体を読んでみると(読み間違えてるかもしれないです。) VALUE埋め込みオブジェクトにあるフラグとancestorメソッドで

irb(main):004:0> Fixnum.ancestors
=> [Fixnum, Integer, Numeric, Comparable, Object, Kernel, BasicObject]

クラスの継承を巡って一緒のkcallがあれば、True。

これで、本当に

すべてがオブジェクトです

と言えるのか。

hanachin commented 9 years ago

2つ目の質問はよく意図が分からなかったんですよねー。

Rubyでは全ての値がオブジェクトで、Objectクラスのインスタンスです。 なので実装上VALUE埋め込みオブジェクトな1とかnilとかtrue/falseみたいな値に対してもメソッドを呼び出せます。

なぜオブジェクトではない思うんですか?(1とか2に対してinstance_variable_setとかが呼び出せないからですか?)

kazuminn commented 9 years ago

なぜオブジェクトではない思うんですか?

Rubyのオブジェクトの定義は、klassのようにclassを示すものとインスタンス変数の配列を持っている。

でも、「VALUE埋め込みオブジェクトは、インスタンス変数の配列を持っていない」のでオブジェクトではないと思いました。

siman-man commented 9 years ago

今、オブジェクト指向における「オブジェクト」と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の返り値が空の配列なので、どこかに参照をもっているか、空の配列を直接決め打ちで返しているかのどっちかなんでしょうね。このあたりはソースを読んで調べるしかなさそうです)

個人的な感想ですが、この辺りをワイワイ議論するのは楽しそうです!

hanachin commented 9 years ago

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
hanachin commented 9 years ago

このあたりの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.

tompng commented 9 years ago
  1. int floatなどはfreezeしてる
  2. 最初からfreezeされてるなら、内部的にはインスタンス変数の配列(空っぽ)を持ってても実は持ってなくても(取得しようとしたら空配列を生成する)挙動は変わらない
  3. 実行速度などの最適化のため、内部的にはオブジェクトじゃないかのように(メモリ上になにも生成しない)しちゃった

言語の内部の実装をどうしているかの話であって、挙動がオブジェクトならオブジェクトと見なしちゃっていいんじゃないかなーと思いました