Here is a short breakdown of how symbols (and other immediates are
implemented):
A variable holds a value. That value is a integer. The value of the
integer determines what it means. For example:
If the integer is odd, then the remaining bits of the integer are a
Fixnum value.
This means that if you do
a = 0
the interpreter stores in the local variable table the value
0x00000001. If you had assigned 4 to a, then the value would be
0x00000041. This allows for all Fixnums to not require additional
memory to represent. The same goes for true, false, nil, and symbols.
For the first 3, they are:
Name Backend Integer Value
=========================
false 0
true 2
nil 4
undef 6 (This isnt accessible from native ruby code, but is used
internally)
For symbols, the least significant byte is 0x0e and the upper 3 bytes
are a integer. The integer is uniquely assigned value for a string.
Think about it as the table index for a string. By using a symbol, you
basically allocate a string once and then refer to it by the index it
occupies in a special symbol table. For example, the first time the
symbol :evan is seen, a string containing "evan" is created and stored
in the symbol table at, say, index 9323. The variable that was assigned
:evan gets assigned
((9223 << 8 ) | 0x0e). The next time :evan is seen, "evan" is looked up
in the symbol table to obtain 9232 again.
So, to review:
a = :evan
a.to_i # => 9232 (the index in the symbol table)
a.object_id # => 2363406 (the index << 8 | 0x0e)
a.to_s # => the reference to the string object located at
index 9232 in the symbol table
The ruby runtime rules take the integer value and apply the rules to
determine what it means. If it's odd, it's a Fixnum immediate value. If
it's 0,2,4, or 6, it's a "core" immediate value. If it has the LSB is
0x0e, it's a symbol. Otherwise, it's a pointer to a memory address that
holds the information about the object.
Thats the end of days leason! Hope it helps!
Evan Webb // evan / fallingsnow.net