Anyone know why this works? Why Ruby was implemented this way?
I tried creating an object_id collision based on this doubling rule,
but it seems that all Fixnum object_ids are odd, and all other object_ids are even (in fact they all seem to end in 8). Clever.
AFAIK, FixNums are implemented as direct values and not C structs that
represent objects. Small integers - which means integers that can be
held in (sizeof(unsigned long int) * 8 -1 = 31 bits). 1 bit is used
for sign and 30 bits for the value.
Here is the INT2FIX macro from Ruby source: #define INT2FIX(i) ((VALUE)(((long)(i))<<1 | FIXNUM_FLAG))
Shift 1 bit to the left, and bitwise OR it with 1. In other words,
object_id = 2n + 1. That explains why your double method works.
I was playing with Ruby and wrote an interesting method:
def double n
n.object_id - 1
end
Anyone know why this works? Why Ruby was implemented this way?
Note that other Ruby implementations (JRuby, Rubinius, IronRuby…) do
not have to keep this contract; it’s best considered as MRI peculiarity.
But yes, I do find this design beautiful – as well as Ruby’s method
lookup: http://www.viddler.com/explore/CobyR/videos/1/
On Wed, Aug 26, 2009 at 5:21 PM, Shot (Piotr S.)[email protected]
wrote:
Note that other Ruby implementations (JRuby, Rubinius, IronRuby…) do
not have to keep this contract; it’s best considered as MRI peculiarity.
But yes, I do find this design beautiful – as well as Ruby’s method
lookup: http://www.viddler.com/explore/CobyR/videos/1/
I don’t know that it’s particularly beautiful; it’s just a side effect
of Fixnums not having any internal state and not actually being
objects in MRI. Because they are “immediates” they don’t actually have
an object_id. As a result, their object_id is just based on their
actual value, 2n+1. All other objects then get stuffed into the
remaining even object_ids, and fixnum.object_id - 1 == fixnum * 2.
On Thu, Sep 3, 2009 at 11:54 AM, Charles Oliver
Nutter[email protected] wrote:
remaining even object_ids, and fixnum.object_id - 1 == fixnum * 2.
And its not that particularly unique to MRI. I know lots of VM
implementations for various languages (Ruby, Smalltalk, JavaScript
…) which use different variations of representing an integer n
smaller than 2**b for some b less than the word length as:
n * 2**flag_shift + int_flag
where flag_shift is some small integer (usually but not always 1) and
int_flag is usually 1 or at least odd, since on most machines a
pointer to an object will be aligned on some even address boundary.
For some reason, Googles V8 JavaScript VM uses an int_flag of 1 and
SETs the low order bit of references which are pointers, at least
according to a video I watched about the implementation.