Ruby Symbols
last modified October 18, 2026
Symbols are lightweight, immutable names in Ruby. A symbol is written with a
leading colon, such as :name, and every occurrence of the same
symbol refers to one shared object. This guide explains what symbols are, how
they differ from strings, and how they are used as hash keys, method names, and
blocks via Symbol#to_proc.
Symbol Literals
A symbol literal starts with a colon. Symbols containing spaces or special
characters use the quoted form :"...". The %i[]
notation builds an array of symbols from words separated by whitespace.
# A symbol is an immutable, interned name status = :active puts status # prints: active puts status.inspect # prints: :active puts status.class # prints: Symbol # Literal syntax: :name, :"with spaces", and %i[] lists puts :"hello world".inspect list = %i[red green blue] p list p list.map(&:class).uniq
The example creates a symbol with :active and shows that puts and inspect display it differently. The class method reports Symbol. It also prints a quoted symbol and builds a list with %i[].
$ ./basics.rb active :active Symbol :"hello world" [:red, :green, :blue] [Symbol]
Symbol vs String Identity
Two identical symbols are the same object, so equal? returns
true. Two identical string literals are separate objects. Symbols
are interned: Ruby stores one copy of each name and reuses it.
# Symbols with the same name are the same object
puts :ruby.equal?(:ruby) # true
puts :ruby.object_id == :ruby.object_id # true
# Strings with the same content are distinct objects
puts "ruby".equal?("ruby") # false
puts "ruby".object_id == "ruby".object_id # false
# Frozen string literals still create separate objects
a = "ruby"
b = "ruby"
puts a == b # true
puts a.equal?(b) # false
puts a.frozen?, :ruby.frozen? # false, true
The example compares symbols and strings. Equal symbols are the same object, so equal? returns true. Equal string literals are separate objects, so equal? returns false.
$ ./identity.rb true true false false true false false true
Memory and Performance
Because each symbol name exists only once, using symbols for repeated identifiers such as hash keys avoids allocating many equal strings. Symbols are also frozen, so they cannot be modified in place. Comparing two symbols checks object identity, which is faster than comparing string contents. Choose strings when you need mutable text and symbols when you need stable names.
Converting with to_sym and to_s
to_sym converts a string to a symbol, and to_s
converts a symbol back to a string. Converting a string to a symbol is useful
for turning user input or configuration names into identifiers.
# String to symbol with to_sym (or intern) name = "username" sym = name.to_sym p sym # :username puts sym.class # Symbol # Symbol to string with to_s (or id2name) back = sym.to_s p back # "username" puts back.class # String # Round trip keeps the same value puts "data".to_sym.to_s == "data" # true puts :data.to_s.to_sym.equal?(:data) # true # Symbols with spaces need quoting p "first name".to_sym # :"first name"
The example converts between strings and symbols with to_sym and to_s. A round trip returns the original value, and a name with spaces needs quoting in symbol form.
$ ./conversion.rb :username Symbol "username" String true true :"first name"
Symbols as Hash Keys and Method Names
Symbol keys (host:) are the idiomatic choice for hashes. A symbol
key and a string key with the same text are different keys. The
send and respond_to? methods accept method names as
symbols, and define_method creates methods from a symbol name.
# Symbols are the usual choice for hash keys
config = { host: "localhost", port: 8080 }
puts config[:host] # localhost
puts config.key?(:port) # true
p config.keys # [:host, :port]
# Symbol keys vs string keys are different keys
mixed = { "host" => "a", host: "b" }
p mixed["host"] # a
p mixed[:host] # b
puts mixed.size # 2
puts "hello".send(:upcase) # HELLO
puts "hello".respond_to?(:upcase) # true
puts "hello".respond_to?(:fly) # false
class Robot
%i[walk talk].each { |a| define_method(a) { "#{a}ing" } }
end
r = Robot.new
puts r.walk # walking
puts r.respond_to?(:talk) # true
The example uses symbols as hash keys and as method names. send calls a method by name, respond_to? checks it, and define_method creates methods from symbols.
$ ./hash_methods.rb localhost true [:host, :port] "a" "b" 2 HELLO true false walking true
Symbol#to_proc
The &:name shorthand passes a symbol as a block. Ruby calls
the named method on each element. This is equivalent to writing an explicit
block, and it works with any method that takes no arguments.
# Symbol#to_proc turns a symbol into a block
words = %w[ruby symbols are fast]
p words.map(&:upcase) # ["RUBY", "SYMBOLS", "ARE", "FAST"]
p words.map(&:length) # [4, 7, 3, 4]
# Equivalent explicit block
p words.map { |w| w.upcase }.equal?(words.map(&:upcase)) # false
p words.map { |w| w.upcase } == words.map(&:upcase) # true
# Works with any method that takes no arguments
p [3, 1, 2].sort.map(&:to_s) # ["1", "2", "3"]
p [[1, 2], [3]].map(&:size) # [2, 1]
The example uses &:upcase, which passes the symbol as a block. It produces the same result as an explicit block, and it works with any method that takes no arguments.
$ ./to_proc.rb ["RUBY", "SYMBOLS", "ARE", "FAST"] [4, 7, 3, 4] false true ["1", "2", "3"] [2, 1]
Symbol Methods
Symbols support many of the same read-only methods as strings, including
length and upcase, which return a new value. The
<=> operator compares symbols alphabetically, and
inspect shows the symbol in its literal form with the leading colon.
# Common Symbol methods sym = :banana puts sym.length # 6 puts sym.upcase.inspect # :BANANA puts sym.to_s.capitalize # Banana # Comparison with <=> (symbols sort by their names) p :apple <=> :banana # -1 p :pear <=> :apple # 1 p :kiwi <=> :kiwi # 0 p %i[pear apple kiwi].sort # [:apple, :kiwi, :pear] # inspect shows the leading colon form p :status # :status puts :status.inspect # :status puts :status.to_s # status
The example uses comparison and inspection methods on symbols. <=> orders symbols alphabetically, sort works on arrays of symbols, and inspect shows the leading colon.
$ ./methods.rb 6 :BANANA Banana -1 1 0 [:apple, :kiwi, :pear] :status :status status
Source References
Learn more from these resources: Ruby Symbol Documentation, String#to_sym, and Proc Documentation.
List all Ruby tutorials.
Author
My name is Jan Bodnar, and I am a passionate programmer with extensive programming experience. I have been writing programming articles since 2007. To date, I have authored over 1,400 articles and 8 e-books. I possess more than ten years of experience in teaching programming.