How does object_id assignment work?
In MRI the object_id
of an object is the same as the VALUE
that represents the object on the C level. For most kinds of objects this VALUE
is a pointer to a location in memory where the actual object data is stored. Obviously this will be different during multiple runs because it only depends on where the system decided to allocate the memory, not on any property of the object itself.
However for performance reasons true
, false
, nil
and Fixnum
s are handled specially. For these objects there isn't actually a struct with the object's data in memory. All of the object's data is encoded in the VALUE
itself. As you already figured out the values for false
, true
, nil
and any Fixnum
i
, are 0
, 2
, 4
and i*2+1
respectively.
The reason that this works is that on any systems that MRI runs on, 0
, 2
, 4
and i*2+1
are never valid addresses for an object on the heap, so there's no overlap with pointers to object data.
Why does 1.object_id always return 3 in Ruby 2.5.1?
The object ID
is calculated from the objects value
plus some additional information. From that calculation you can derive the values you are seeing in your examples.
for more information in details read these SO post:
- How does
object_id
assignment work? - Why is the
object_id
of aFixnum
an odd number?
Ruby object to_s what is the encoding of the object id?
Think of the object_id
, or __id__
as the "pointer" for the object. It is not technically a pointer, but does contain a unique value that can be used to retrieve the internal C VALUE
.
There are patterns to the value it has for some data types, as you can see with its hexadecimal representation with to_s
. I am will not go into all the details, as there are already numerous answers on SO explaining, and already linked from comments, but integers (up to a FIXNUM_MAX
, have predictable values, and special constants like true
, false
, and nil
will always have the same object_id
in every run.
To put simply, it is nothing more than a number, and shown as a hexadecimal (base 16) value, not any actual "encoding" or cypher.
Going to expand upon this a bit more in light of your latest edits to the question. As you posted, the hexadecimal number you see in to_s
is the value of the internal C VALUE
of the object. VALUE
is a C data type (unsigned, pointer size number) that every Ruby object is represented as in C code. As @Stefan pointed out in a comment, for non-integer types (I speak only for MRI version), it is twice the value of the object_id
. Not that you probably care, but you can shift the bits of an integer to predict the value for those.
Therefore, using you example.
A value of 0x00007fac5eb6afc8
is simple hexadecimal notation for a number. It uses a base 16 counting system as opposed to the base 10 decimal system we are more used to in everyday life. It is simply a different way of looking at the same number.
So, using that logic.
a = 0x00007fac5eb6afc8
#=> 140378300133320 # Decimal representation
a /= 2 # Remember, non-integers are half of this value
#=> 70189150066660 # Your object_id
object_id of keys (and some other objects) are always the same. Why is that?
So i searched over the internet and found out this article http://threebrothers.org/brendan/blog/memory-and-ruby-symbols/ . I come to know that ruby process maintains a symbol table which has one entry per symbol as long as the process exists, so whenever a new symbol is created ruby do a search in that symbol table and if not exists it creates a new one to the last entry just like the entries in database tables.
More sources that can help:
Id2sym & symbol.object_id
Why was the object_id for true and nil changed in ruby2.0?
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_id
s of other immediate values have been changed to accomodate this change.
You can see this change by looking at the object_id
s 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
Difference on working of object_id method with Fixnum object and String object
Fixnums are immutable objects in Ruby. There is exactly one instance created and you work with that object "directly". i.e references are not used unlike other regular objects. So They have a fixed object_id. This is ok because you have only one instance of the object.
But when you write "hello", a new string object is created. And in the same script, if you give another "hello", even though they have same content, a new object is created. Hence the different object_ids.
Why does Ruby tend to assign object IDs in descending order?
Handwaving over many details, ruby allocates a chunk of the heap to put objects in:
1 | 2 | 3 | 4 | 5
Then traverses them in-order and adds them to a linked-list of free objects. This causes them to be in reverse order on the linked-list:
freelist → NULL
freelist → 1 → NULL
freelist → 2 → 1 → NULL
freelist → 3 → 2 → 1 → NULL
freelist → 4 → 3 → 2 → 1 → NULL
freelist → 5 → 4 → 3 → 2 → 1 → NULL
When allocating an object ruby uses the first item on the linked list:
object = freelist
freelist = object.next_free
So the freelist now looks like:
freelist → 4 → 3 → 2 → 1 → NULL
and further allocated objects will appear in reverse order across small allocations.
When ruby needs to allocate a new chunk of heap to store more objects you'll see the object_id jump up then run down again.
Why is the `object_id` of a `Fixnum` an odd number?
This is done so that integers do not take up all the room for other objects. In Ruby all other Objects have even object_id's, they go in between. The integer object_id's are very easily converted to their value: the last bit (always a 1) is chopped off.
Integers are a bit fake objects, they are no more than an id and a shared list of methods.
Can we access the objects we created in ruby using their object _ids in ruby?
How an object ID is “assigned” depends on the Ruby implementation and other factors like the OS bitness. For example, in CRuby nil.object_id
returns 4
on 32-bit and 8
on 64-bit.
Additionally nil
is a so called immediate value. true
, false
, fixnums (small integers) and sometimes even floats are other immediate values. They have fixed IDs for the following reasons:
- they're passed by value and not by reference like the other (dynamically allocated) objects
- there's only one
nil
, onetrue
, one19
, etc. however there can be two different arrays
See the documentation of BasicObject#object_id
. You can also click to toggle the source to get a look at the CRuby implementation.
Call ObjectSpace._id2ref
to retrieve an object by ID:
id = nil.object_id
ObjectSpace._id2ref(id) # => nil
In some implementations that method may not be implemented or really slow. According to matz it was originally a hack needed to implement weakref
but current versions don't call it anymore.
Related Topics
Reducing N+1 Queries Using the Bullet and Rspec Gems
What Does @@Variable Mean in Ruby
Rails Keeps Telling Me That It's Not Currently Installed
Rhc Setup Gives Error 'No Such File Dl/Import'
How to Get a Specific Output Iterating a Hash in Ruby
How to Count Duplicate Elements in a Ruby Array
Incompatible Character Encodings: Ascii-8Bit and Utf-8
What Does 'Monkey Patching' Exactly Mean in Ruby
How to Get a Single Character Without Pressing Enter
Nokogiri/Xpath Namespace Query
Usage of Attr_Accessor in Rails
Altering the Primary Key in Rails to Be a String
Block Definition - Difference Between Braces and Do-End
Checking If a Variable Is Defined