So while in the #RubyOnRails IRC channel late at night (never a good idea) some silly conversation occured:

(someone gists some code)
sevenseacat: empty array seems the silly thing to have
Tarential: sometimes I like to add empty arrays, you know, just in case I need them later
Tarential: so they’re close at hand
tagrudev: little kittens die when you define an unused var
brianpWins: but if you do want to leave empty arrays around. Make them a symbol so it only allocates once =) :[]
Tarential: Now that’s thinking.

Then some time passed and I ended up throwing a pastie back into the channel with the following code:

class Symbol
  def to_a
    @array ||= []

  def <<(val)
    to_a << val

  alias_method :previous_inspect, :inspect
  def inspect
    if to_a && to_s == "[]" 

=> []

:[] << 1 << 2 << 3 << 4
=> [1, 2, 3, 4]

=> Symbol

=> [1, 2, 3, 4]

=> [1, 2, 3, 4]

Mostly usless but I did find out one interesting piece of information. The Symbol has no public creation interface other then it’s standard definition. I’m assuming at this point it drops down to the C level but I couldn’t leave that stone unturned. I put the word out I was in search of the Symbol implementation in Ruby. I asked some friends, tweeted about it and poked around on IRC.

REPL in the Pry runtime environment
@banister (who brings you awesome projects like Pry) ended up giving me a nice intro to what happens when you put :cats into a ruby runtime environment.

I’ll keep this brief and in laymans terms. People who know much more about this feel free to email me with corrections or improvements. Keep in mind this information was explained at a very high level so it wouldn’t all go over my head.

At a very basic level the runtime is performing a simple REPL (Read, Evaluate, Print, Loop.)

read --> eval --> puts #inspect on eval output --> loop

The Read simply reads in your input. In our case $ :cats

The Eval gets significantly deeper. In the case the value entered is a Symbol (or other immediates) it is stored directly in the VALUE pointer. @banister provided me with the following gist to show how the Symbol is stored: pry_gist.rb

(this is only a small piece of the total evalution process.)

rb_obj_id(VALUE obj)
     *                32-bit VALUE space
     *          MSB ------------------------ LSB
     *  false   00000000000000000000000000000000
     *  true    00000000000000000000000000000010
     *  nil     00000000000000000000000000000100
     *  undef   00000000000000000000000000000110
     *  symbol  ssssssssssssssssssssssss00001110
     *  object  oooooooooooooooooooooooooooooo00        = 0 (mod
     *  fixnum  fffffffffffffffffffffffffffffff1
     *                    object_id space
     *                                       LSB
     *  false   00000000000000000000000000000000
     *  true    00000000000000000000000000000010
     *  nil     00000000000000000000000000000100
     *  undef   00000000000000000000000000000110
     *  symbol   000SSSSSSSSSSSSSSSSSSSSSSSSSSS0        S...S % A = 4
        (S...S = s...s * A + 4)
     *  object   oooooooooooooooooooooooooooooo0        o...o % A = 0
     *  fixnum  fffffffffffffffffffffffffffffff1        bignum if
     *  where A = sizeof(RVALUE)/4
     *  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 (TYPE(obj) == T_SYMBOL) {
        return (SYM2ID(obj) * sizeof(RVALUE) + (4 << 2)) | FIXNUM_FLAG;
    if (SPECIAL_CONST_P(obj)) {
        return LONG2NUM((SIGNED_VALUE)obj);

He added:

a normal object created via for example are normally allocated on the heap and they go through a proper initialization process.

error: cannot access named params by position error: cannot access named params by position

Then the Print runs a simple #inspect on the Symbol and returns => :cats to you.

After that we Loop for more input.

So where does this leave us?
I ended up getting a great introduction to some things going on in my every day environment that I simply take for granted. It all came out of some late night nonsense and exploration and now I feel like new doors have opened and I’m going to have to go through.

I encourage you to poke around. We write code all day long but really finding out what’s going on can be new and exciting. So open up a Ruby class and break something!