2

Using ruby-hacking-guide site, I've found that fixnum << 8 | 1 is object_id of any fixnum.
I've tried using similar approach with symbol.

#define ID2SYM(x) ((VALUE)(((long)(x))<<8|SYMBOL_FLAG))

When shifting 8 bits left, x becomes a multiple of 256, that means a multiple of 4. Then after with a bitwise or (in this case it’s the same as adding) with 0×0e (14 in decimal)

I have tried it with :a(:a.object_id = 175_976, on my 32-bit system):

  1. ASCII number of a is 97.
  2. 97 << 8 = 24832
  3. 24832 | 14 = 24_846

So it's not even close to :a's object id.

I've checked source of object_id and found this:

  *  sizeof(RVALUE) is
  *  20 if 32-bit, double is 4-byte aligned
  *  24 if 32-bit, double is 8-byte aligned
  *  40 if 64-bit
  */
 if (SYMBOL_P(obj)) {
     return (SYM2ID(obj) * sizeof(RVALUE) + (4 << 2)) | FIXNUM_FLAG;

I got ~ 500 000, which is bad value.

So what I'm missing? How to calculate object_id of symbol?

Darek Nędza
  • 1,420
  • 1
  • 12
  • 19

1 Answers1

1

The ID value that you calculate from a symbols object_id doesn’t directly represent the string content of that symbol. It is an index into a table that Ruby maintains containing the string. When you use a symbol in Ruby then if that symbol hasn’t been used before in the current process it will be given the ID value of the next free slot in the symbol table.

This means that a given symbol won’t always have the same ID value. The ID value associated a Ruby processes symbols will depend on the order that they are created.

You can see this by starting a new Ruby process, creating a new symbol and looking at its object_id, and then repeating with a different symbol name. The object_id should be the same in both cases, since it will be referring to the next free spot in the symbol table. You need to be careful doing this as Ruby defines a lot of symbols itself, so if you use one of these you’ll get different results.

For example, an irb session:

2.1.0 :001 > Symbol.all_symbols.find {|sym| sym.to_s == 'matt' }
 => nil 
2.1.0 :002 > :matt.object_id
 => 542248

And another:

2.1.0 :001 > Symbol.all_symbols.find {|sym| sym.to_s == 'banana' }
 => nil 
2.1.0 :002 > :banana.object_id
 => 542248 

Here we first check to see if the name we are going to use doesn’t already exist as a symbol, then we create the symbol and look at its object_id. In both cases it is the same 542248, corresponding to an ID of 2118, even though they have different names (these values may differ on different systems or Ruby versions).

matt
  • 78,533
  • 8
  • 163
  • 197