RubyGuides
Share this post!

How Are Symbols And Strings Different?

Have you ever wondered about the differences between symbols & strings?

Let’s talk about that!

Strings are used to work with data.

Symbols are identifiers.

That’s the main difference. Symbols are not just “frozen strings“, they have different uses than strings.

When to Use Symbols

One of the most common uses for symbols is to represent method & instance variable names.

Example:

attr_reader :title

The :title after attr_reader is a symbol that represents the @title instance variable.

You can also use symbols as hash keys.

Example:

hash = {a: 1, b: 2, c: 3}

The benefits?

Symbols look better, they are immutable & if you benchmark string keys vs symbols keys you will find that string keys are about 1.70x slower.

Symbols can also be used in metaprogramming methods like send:

[1,2,3].send(:first)

In Summary:

You should use symbols as names or labels for things (like methods) & use strings when you care more about the data (individual characters).

Converting Between Strings & Symbols

Sometimes you will get a symbol back from some method call & you will need to convert it into a string so you can compare it with other strings or do some other string operation.

You can do this using the to_s method.

For example, when using method_missing you get the name of the missing method as a symbol & you may want to check if this method name matches a certain pattern (like ending in ?).

Example:

def method_missing(method_name, *args, &block)
  if method_name.to_s[-1] == "?"
    # do something
  else
    super
  end
end

You can also convert a string into a symbol.

The method to do this is String#to_sym:

"rubyguides".to_sym

:rubyguides

Creating An Array Of Symbols

If you want to create an array of symbols you can use this code:

symbols = %i(a b c)

[:a, :b, :c]

This saves you from having to type the colons & the commas.

Similar to the string version %w:

strings = %w(a b c)

["a", "b", "c"]

Ruby Symbols Video

Symbol GC

Another interesting fact about symbols is that there are different types, and the reason for that is that symbols were not garbage collected before Ruby 2.2, which means that they where not cleaned up from memory when no longer needed like regular Ruby objects (strings, hashes, arrays…).

You can see an example here:

p Symbol.all_symbols.size
# 2443

('aa'..'aj').map(&:to_sym)

GC.start
p Symbol.all_symbols.size
# 2453

You will notice that the total count of symbols increases by 10, just like you would expect since we are creating 10 new symbols.

But since Ruby 2.2 these symbols are removed from memory because they are just temporary & not being used by something else in this code.

If you try this code on a version of Ruby that has Symbol GC enabled both symbol counts will be the same.

Some symbols will never be removed from memory, these are called “immortal symbols”.

You can count them using the ObjectSpace module:

require 'objspace'

ObjectSpace.count_symbols

{
  :mortal_dynamic_symbol=>3,
  :immortal_dynamic_symbol=>5,
  :immortal_static_symbol=>3663,
  :immortal_symbol=>3668
}

Notice that symbols created directly, like :a1 will automatically become immortal symbols. Creating a new method will also create an immortal_static_symbol to go with it.

So where do mortal symbols come from?

From strings converted into symbols with the to_sym method.

You can check this yourself using ObjectSpace.count_symbols.

And if you are wondering what’s an immortal_dynamic_symbol, it’s a symbol that has been promoted from mortal to immortal. This can happen when you create a method with the name of a mortal symbol.

Summary

On this article you learned:

  • Symbols are immutable
  • Symbols are not pointer to values, they are values themselves
  • Strings are for data & symbols are for identity
  • How to convert between strings & symbols
  • Symbol GC was introduced in Ruby 2.2 to clean up temporary symbols

Hope you learned something new!

Please share this post so it can reach more people 🙂

4 comments
Dmytro says a few months ago

Great work Jesus, i find your posts helpful & enjoyable 🙂

    Jesus Castello says a few months ago

    Thank you Dmytro! 🙂

Mike says a few months ago

In the method_missing example, is it necessary to call super(args)? I thought just super would automatically pass the same args.

    Jesus Castello says a few months ago

    Hi Mike,
    you are correct, it’s not necessary & it works as you say 🙂

Comments are closed