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.

Sam R.
  • 16,027
  • 12
  • 69
  • 122
LuckyLuke
  • 47,771
  • 85
  • 270
  • 434
  • 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. :) – Andrew Grimm Jul 15 '12 at 23:44
  • Possible duplicate of [Understanding Symbols In Ruby](http://stackoverflow.com/questions/2341837/understanding-symbols-in-ruby) – David Hoelzer Aug 30 '16 at 11:33

5 Answers5

36

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

Sergio Tulentsev
  • 226,338
  • 43
  • 373
  • 367
  • 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? – LuckyLuke Jul 12 '12 at 08:12
  • 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. – Sergio Tulentsev Jul 12 '12 at 08:15
  • So a symbol is a string with the properties equal to `static` and immutable in other languages? – LuckyLuke Jul 12 '12 at 08:17
  • @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`. – Sergio Tulentsev Jul 12 '12 at 08:20
  • I am starting to understand a little better but you say that if you have a string that appears often and you don't want to do something "funky" to it, then it may 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? And is the reason that it is never garbage collected? – LuckyLuke Jul 12 '12 at 08:32
  • So you use symbols only for naming internal "stuff" such as hash keys (that you make as a programmer, not from user), in attr_accessor, attr_reader etc? – LuckyLuke Jul 12 '12 at 09:07
  • I will wait a little to accept the answer, I may come up with a few other questions. I will accept and give you the 500 points bounty as promised. – LuckyLuke Jul 12 '12 at 09:54
  • 1
    @yozzz: thanks! Removed the broken link, as the rest of the answer should be enough. – Sergio Tulentsev Aug 11 '16 at 08:54
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.

Todd A. Jacobs
  • 81,402
  • 15
  • 141
  • 199
  • `Object#send` does **not** require a symbol. – Sergio Tulentsev Dec 09 '15 at 12:21
  • 1
    @SergioTulentsev While current versions of MRI accept string arguments for this method, [earlier versions did not](http://ruby-doc.org/core-1.8.7/Object.html#method-i-send). 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. – Todd A. Jacobs Dec 09 '15 at 15:19
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).

Sam R.
  • 16,027
  • 12
  • 69
  • 122
steenslag
  • 79,051
  • 16
  • 138
  • 171
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.

Rich
  • 15,048
  • 2
  • 66
  • 119
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/