【一人 bugs.ruby Advent Calendar 2020】[Feature #17292] id outputed by inspect and to_s output does not allow to find actual object_id and vice-versa【21日目】
一人 bugs.ruby Advent Calendar 2020 21日目の記事になります。
[Misc #17199] id outputed by inspect and to_s output does not allow to find actual object_id and vice-versa
Ruby 2.7 から #inspect
( #to_s
) と #__id__
が返すアドレスの関連性が一致しなくなったという報告チケットなります。
どういうことかというと Ruby 2.7 から以下のように #__id__
が返す値が変わりました。
obj = Object.new # Ruby 2.7 から #__id__ の値が変わった p "#__id__=#{obj.__id__}" # Ruby 2.6 => "#__id__=47458875463160" # Ruby 2.7 => "#__id__=60"
これと #inspect
がどう関係あるのかというと #__id__
から #inspect
で表示されるアドレスを推論できていたんですが、それが上記の変更でできなくなりました。
obj = Object.new p "#inspect=#{obj.inspect}" # => "#inspect=#<Object:0x00005653c2d3abf0>" # Ruby 2.6 では __id__ の結果をシフトすると inspect に表示される id と同じになっていた # しかし Ruby 2.7 ではできなくなっている p "shifted_id=#{(obj.__id__ << 1).to_s(16)}" # Ruby 2.6 => "shifted_id=5653c2d3abf0" # Ruby 2.7 => "shifted_id=78"
これにより何が起きるのかというと例えば #inspect
の出力の 0x00005653c2d3abf0
というアドレスから __id__
を推論する事ができたので次のように ObjectSpace._id2ref
で実際のオブジェクトの値を取得する事ができていました。
しかし、 Ruby 2.7 の変更によりこれはできなりました。
o = Object.new # 任意の __id__ からそのオブジェクトが取得できる pp ObjectSpace._id2ref(o.__id__) # inspect から id を取得してそれを元にしてオブジェクトを取得する事ができた # これが Ruby 2.7 からは動作しなくなっている id_from_inspect = o.inspect[/#<Object:(.*)>/, 1].to_i(16) pp ObjectSpace._id2ref(id_from_inspect >> 1)
こんな仕様があったんですね…。
例えば Object#inspect
をログ出力しているような場合にその出力されたアドレスから『実際のオブジェクトを参照したい』みたいな場合に利用できるのかなあ、とは思いました。