doubling numbers with Object#object_id

E

EbFFA

I was playing with Ruby and wrote an interesting method:

def double n
n.object_id - 1
end

irb> double 5
=> 10
irb> double 1
=> 2
irb> double 0
=> 0
irb> double -101
=> -202
irb> double 100000001
=> 200000002
irb> double 10000000000 # into Bignum territory now
=> -606548539

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_id`s are odd, and all other
object_id`s are even (in fact they all seem to end in 8). Clever.
 
N

Nilesh Trivedi

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 =3D 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 =3D 2n + 1. That explains why your double method works.

cheers
nilesh
 
N

Nilesh Trivedi

All other Ruby objects are allocated on addresses that are multiples
of 4 to avoid clash with FixNum. So Object ID is always even for them.

cheers
nilesh
 
E

EbFFA

Aah that explains everything, thankyou. That's a very beautiful
system. Makes me want to design my own interpreter and take part in
such things.

All other Ruby objects are allocated on addresses that are multiples
of 4 to avoid clash with FixNum. So Object ID is always even for them.

cheers
nilesh
 
C

Charles Oliver Nutter

EbFFA:




Note that other Ruby implementations (JRuby, Rubinius, IronRuby=E2=80=A6)= do
not have to keep this contract; it=E2=80=99s best considered as MRI pecul= iarity.
But yes, I do find this design beautiful =E2=80=93 as well as Ruby=E2=80= =99s 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 =3D=3D fixnum * 2.

- Charlie
 
R

Rick DeNatale

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 =3D=3D 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.


--=20
Rick DeNatale

Blog: http://talklikeaduck.denhaven2.com/
Twitter: http://twitter.com/RickDeNatale
WWR: http://www.workingwithrails.com/person/9021-rick-denatale
LinkedIn: http://www.linkedin.com/in/rickdenatale
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,997
Messages
2,570,241
Members
46,831
Latest member
RusselWill

Latest Threads

Top