17

First time I tried learning Ruby was 2 years ago, now I have started again. The reason I stopped was because I could not understand the Symbol class. And now I am at the same point again, completely lost in when and why you use Symbols. I have read the other posts on Stackoverflow as well as Googled for several explanations. But I do not understand it yet.

First I thought symbols was just a way to create some sort of "named constant" without having to go through the same process as in let say Java.

:all 

instead of making a constant with an arbitrary value public static final String ALL = 8;

However it does not make much sense when you use it in e.g. attr_accessor :first_name etc. Are Symbols just a lightweight String class? I am having problems understanding how I should interpret, when and how to use symbols both in my own classes and in frameworks.

2
  • 11
    If it makes you feel any better, the creators of Ruby themselves don't really understand when to use strings, and when to use symbols. Class.new.methods returned an array of strings in 1.8, and an array of symbols in 1.9. :) Commented Jul 15, 2012 at 23:44
  • Possible duplicate of Understanding Symbols In Ruby Commented Aug 30, 2016 at 11:33

5 Answers 5

36
+500

In short, symbols are lightweight strings, but they also are immutable and non-garbage-collectable.

You should not use them as immutable strings in your data processing tasks (remember, once symbol is created, it can't be destroyed). You typically use symbols for naming things.

# typical use cases

# access hash value
user = User.find(params[:id])

# name something
attr_accessor :first_name

# set hash value in opts parameter
db.collection.update(query, update, multi: true, upsert: true)  

Let's take first example, params[:id]. In a moderately big rails app there may be hundreds/thousands of those scattered around the codebase. If we accessed that value with a string, params["id"], that means new string allocation each time (and that string needs to be collected afterwards). In case of symbol, it's actually the same symbol everywhere. Less work for memory allocator, garbage collector and even you (: is faster to type than "")

If you have a simple one-word string that appears often in your code and you don't do something funky to it (interpolation, gsub, upcase, etc), then it's likely a good candidate to be a symbol.

However, does this apply only to text that is used as part of the actual program logic such as naming, not text that you get while actually running the program...such as text from the user/web etc?

I can not think of a single case where I'd want to turn data from user/web to symbol (except for parsing command-line options, maybe). Mainly because of the consequences (once created symbols live forever).

Also, many editors provide different coloring for symbols, to highlight them in the code. Take a look at this example

symbol vs string

Sign up to request clarification or add additional context in comments.

8 Comments

So the reason for having Symbol is that String is mutable, and hence the programmer is left to enhance the performance of the program by himself/herself by using the immutable class Symbol?
You should not use them as immutable strings in your data processing tasks (remember, once symbol is created, it can't be destroyed). You typically use symbols for naming things.
So a symbol is a string with the properties equal to static and immutable in other languages?
@Dude: yes, you could say that. Note that symbol can not be substituted instead of string. It looks like a string, but from ruby's perspective, it isn't one. You can always cast, :foo.to_s.
@yozzz: thanks! Removed the broken link, as the rest of the answer should be enough.
|
12

The O'Reilly Ruby Cookbook (p. 15) quotes Jim Weirich as saying:

  • If the contents (the sequence of characters) of the object are important, use a string.
  • If the identity of the object is important, use a symbol.

Symbols are generally used as hash keys, because it's the identity of the key that's important. Symbols are also required when passing messages using certain methods like Object#send.

2 Comments

Object#send does not require a symbol.
@SergioTulentsev While current versions of MRI accept string arguments for this method, earlier versions did not. Even so, unless the implementation has changed again, #send converts string arguments to symbols because that's how Ruby identifies method names internally. Your mileage (and specific implementations) may vary.
8

A Ruby implementation typically has a table in which it stores the names of all classes, methods and variables. It refers to say a method name by the position in the table, avoiding expensive string comparisons. But you can use this table too and add values to it: symbols.

If you write code that uses strings as identifiers rather than for their textual content, consider symbols. If you write a method that expects an argument to be either 'male' or 'female', consider using :male and :female . Comparing two symbols for equality is faster than strings (that's why symbols make good hash keys).

Comments

5

Symbols are used for naming things in the language: the names of classes, the names of methods etc. These are very like strings, except they can never be garbage collected, and testing for equality is optimised to be very quick.

The Java implementation has a very similar thing, except that it is not available for runtime use. What I mean is, when you write java code like obj.someMethod(4), the string 'someMethod' is converted by the compiler into a symbol which is embedded in a lookup table in the .class file. These symbols are like 'special' strings which are not garbage collected, and which are very fast to compare for equality. This is almost identical to Ruby, except that Ruby allows you to create new symbols at runtime, whereas Java only allows it at compile time.

This is just like creating new methods -- Java allows it at compile time; Ruby allows it at runtime.

Comments

1

After ruby version 2.2 symbol GC was removed, so now mortal symbols i.e when we convert string to symbol ("mortal".to_sym) gets cleaned up from memory.

check this out:

require 'objspace'
ObjectSpace.count_symbols
{
  :mortal_dynamic_symbol=>3,
  :immortal_dynamic_symbol=>5,
  :immortal_static_symbol=>3663,
  :immortal_symbol=>3668
}

source: https://www.rubyguides.com/2018/02/ruby-symbols/

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.