16

I came across this ruby object_id allocation question sometime back and then read this awesome article which talks about VALUE and explains why object_id of true, nil and false the way they are. I have been toying with ruby2.0 object_id when I found the apparent change that has been made regarding object_id of true and nil.

forbidden:~$ ruby -v
ruby 2.0.0p0 (2013-02-24 revision 39474) [x86_64-linux]
forbidden:~$
forbidden:~$ irb
irb(main):001:0> true.object_id
=> 20
irb(main):002:0> false.object_id
=> 0
irb(main):003:0> nil.object_id
=> 8
irb(main):004:0> exit
forbidden:~$
forbidden:~$ rvm use 1.9.3
Using /home/forbidden/.rvm/gems/ruby-1.9.3-p392
forbidden:~$ ruby -v
ruby 1.9.3p392 (2013-02-22 revision 39386) [x86_64-linux]
forbidden:~$
forbidden:~$ irb
irb(main):001:0> true.object_id
=> 2
irb(main):002:0> false.object_id
=> 0
irb(main):003:0> nil.object_id
=> 4

tl;dr: The values for true and nil were respectively 2, 4 in 1.9.3 and 1.8.7, but have been changed to 20, 8 in ruby2.0.0 - even though the id of false remains the same i.e. 0 and the ids for Fixnum maintains the same old 2n+1 pattern.

Also, the way Fixnum and Bignum are implemented is still the same in 2.0.0 as the example given in the above mentioned article also runs just the same way it used to:

irb(main):001:0> 
irb(main):002:0* ((2**62)).class
=> Bignum
irb(main):003:0> ((2**62)-1).class
=> Fixnum
irb(main):004:0>

What's the reason behind this object_id change?

Why was this change made? How is this going to help developers?

Community
  • 1
  • 1
Bharadwaj Srigiriraju
  • 2,196
  • 4
  • 25
  • 45
  • maybe they added some more internal objects, so it changed these values...they're not guaranteed to be any number are they? Anyway you could ask on ruby-devel mailing list... – rogerdpack Mar 19 '13 at 18:06
  • Why does it matter if `true.object_id` and `nil.object_id` changed? They're not guaranteed to have any particular values and I doubt they're even guaranteed to be the same across separate invocations of `ruby`. – mu is too short Mar 19 '13 at 18:06
  • I am using Ruby2.0 in windows machine,for me nothing changed. – Arup Rakshit Mar 19 '13 at 18:13
  • @iAmRubuuu: I think this change has only been made in the 64 bit version. I have tried it on both 32 and 64 bit versions on my windows machine, and the change appeared only in the 64 bit ruby2.0 installation. – Bharadwaj Srigiriraju Mar 19 '13 at 18:41
  • @muistooshort: May be it doesn't matter if they change their object_ids, as it looks like a 'not so used' feature (can anyone use something like that in their programming at all?) - but the ids were only changed in ruby2.0 and not in 1.9 or 1.8. My curiosity was: What made them 'preserve' these ids for more than 2 generations and what's so different now that they had to change it? To be frank, I was expecting some answer like that article I mentioned... there's nothing wrong about knowing internals right? ;) – Bharadwaj Srigiriraju Mar 19 '13 at 18:47
  • 2
    Seems to be something to do with “flonums” – a technique for speeding up floating point calculations on 64-bit: https://github.com/ruby/ruby/blob/v2_0_0_0/include/ruby/ruby.h#L383-431 and http://www.ruby-forum.com/topic/4404164. – matt Mar 19 '13 at 21:23
  • @matt: Looks like you're right!! Have to dig deeper into why they have been introduced... Consider posting it as an answer. I will accept it. Thanks! – Bharadwaj Srigiriraju Mar 20 '13 at 14:05
  • 5
    I can't believe three people have voted to close this. – Andrew Grimm Mar 21 '13 at 22:51

1 Answers1

19

A look at the Ruby source where these values are defined suggests that this has something to do with “flonums” (also see the commit where this was introduced). A search for ”flonum” came up with a message on the Ruby mailing list discussing it.

This is a technique for speeding up floating point calculations on 64 bit machines by using immediate values for some floating point vales, similar to using Fixnums for integers. The pattern for Flonums is ...xxxx xx10 (i.e. the last two bits are 10, where for fixnums the last bit is 1). The object_ids of other immediate values have been changed to accomodate this change.

You can see this change by looking at the object_ids of floats in Ruby 1.9.3 and 2.0.0.

In 1.9.3 different floats with the same value are different objects:

1.9.3p385 :001 > s = 10.234
 => 10.234 
1.9.3p385 :002 > t = 10.234
 => 10.234 
1.9.3p385 :003 > s.object_id
 => 2160496240 
1.9.3p385 :004 > t.object_id
 => 2160508080 

In 2.0.0 they are the same:

2.0.0p0 :001 > s = 10.234
 => 10.234 
2.0.0p0 :002 > t = 10.234
 => 10.234 
2.0.0p0 :003 > s.object_id
 => 82118635605473626 
2.0.0p0 :004 > t.object_id
 => 82118635605473626 
matt
  • 78,533
  • 8
  • 163
  • 197