In the last entry, I talked about Ruby VALUEs and what they mean. A few readers brought up some good points - namely that object_id’s and VALUEs look very similiar:
If we go inside Ruby for a second, here’s how the object_id is calculated:
VALUE
rb_obj_id(VALUE obj)
{
if (SPECIAL_CONST_P(obj)) {
return LONG2NUM((long)obj);
}
return (VALUE)((long)obj|FIXNUM_FLAG);
}
You can trace back the SPECIAL_CONST_P macro to point to a few other macros which point to a few other macros, etc.
What ends up happening, in general, is that the VALUE and the object_id are the same.
irb(main):001:0> "some_string".object_id
=> 1136556
irb(main):002:0> nil.object_id
=> 4
irb(main):003:0> false.object_id
=> 0
irb(main):004:0> true.object_id
=> 2
irb(main):005:0> 5.object_id
=> 11
Why does 5 have an object_id of 11? Well, don’t forget that Fixnums are stored in the upper 31 bits, which means a shift left of one. We also use the lowest bit to mark that it is a Fixnum.
Thus 0×0101 (5) becomes 0×1011 (11).
If we look back at our string object from above, its VALUE (1136556) correlates to 0b1000101010111110101100. Note that the lower two bits are 0 - they have to be if they represent at least a 4 byte aligned memory address (see previous entry for why).
What about symbols?
irb(main):002:0> :foo.object_id
=> 3895566
irb(main):004:0> :foo.to_i
=> 15217
So :foo’s object_id is 0b1110110111000100001110 and its to_i gives 0b11101101110001. First notice that the object_id has a 1 in the 2nd lowest bit. This again denotes a special type. Also note that there’s something similiar between the object_id and the to_i value - in fact, if you chop off the right most 8 bits from the object_id, you get the same number as to_i.
This may come into play later.