Объяснение шестнадцатеричного идентификатора объекта Ruby

Вы когда-нибудь задумывались, откуда взялось шестнадцатеричное значение и что оно означает?

В какой-то момент своей жизни вы, вероятно, спросили себя: что это за странное шестнадцатеричное значение рядом с именем класса, когда вы создаете объект или запускаете метод проверки?

Короткий ответ: это измененный идентификатор объекта. Могу себе представить, что этот ответ вас не удовлетворит. Меня это тоже не удовлетворяет. Итак, вот длинный ответ:

В Ruby Interpreter (MRI) Matz’а object_id совпадает со VALUE объекта в C (в котором записан MRI). Это ЗНАЧЕНИЕ является указателем на место в памяти, где хранится объект (данные). Это справедливо для любого объекта, за некоторыми исключениями. Это основная причина, по которой экземпляры одного и того же приложения будут возвращать разные идентификаторы для одного и того же объекта.

Теперь я использовал слово «совпадает», потому что ЗНАЧЕНИЕ и object_id тесно связаны, даже в некоторых случаях они абсолютно одинаковы.

Важно знать, что VALUE имеет отдельные пространства имен для разных типов данных.

        VALUE space
false   00000000000000000000000000000000
true    00000000000000000000000000000010
nil     00000000000000000000000000000100
symbol  ssssssssssssssssssssssss00001110
object  oooooooooooooooooooooooooooooo00
fixnum   fffffffffffffffffffffffffffffff1

То же самое и с object_id.

        object_id space
false   00000000000000000000000000000000
true    00000000000000000000000000000010
nil     00000000000000000000000000000100
symbol  0000SSSSSSSSSSSSSSSSSSSSSSSSSSS0
object  ooooooooooooooooooooooooooooooo0       
fixnum   fffffffffffffffffffffffffffffff1

Из приведенных выше примеров вы можете понять, что nil, true, false и fixnums одинаковы для обоих. С другой стороны, объекты сдвигаются на один бит влево от соответствующего ЗНАЧЕНИЯ.

Поэтому, когда вы запускаете метод object_id, вы можете увидеть представление из пространства object_id. Когда вы запускаете метод проверки, вы можете увидеть представление из пространства ЗНАЧЕНИЕ, преобразованное в шестнадцатеричное число.

obj = Object.new      #=> #<Object:0x00007fb7981e4068> 
obj.object_id         #=> 70213253931060 
obj.object_id << 1    #=> 140426507862120 
_.to_s(16)            #=> "7fb7981e4068"

И это может быть все. Но один вопрос остается без ответа: почему nil, true, false и fixnums не ведут себя так?

Ответ: по соображениям производительности. Поскольку эти объекты интенсивно используются повторно, ЗНАЧЕНИЕ не содержит указатель на место в памяти, но содержит сам объект (данные).

Из приведенных ниже списков кода видно, что идентификаторы объектов для false, true, nil и fixnums (n) равны 0, 2, 4 и 2n+1 соответственно. Они никогда не являются действительными адресами, поэтому их нельзя путать с указателями.

false.object_id       #=> 0
true.object_id        #=> 2
nil.object_id         #=> 4
1.object_id           #=> 3
2.object_id           #=> 5
10.object_id          #=> 21