Skip to content

/compare/ruby/symbol-vs-string

Ruby symbol vs string: :name vs "name"

The commands on this page have not been executed by our verification runner yet.updated
tool
Ruby
compares
Symbol (:name) vs String ("name")

A Ruby symbol (:name) is an immutable, interned identifier: every :name in the program is the same object. A string ("name") is text, and each string literal normally creates a new object that can be changed. Use symbols for names the code uses internally (hash keys, method names, options, states) and strings for data (user input, file contents, output). The two are not interchangeable as hash keys: h[:id] and h["id"] look up different entries.

Differences

SymbolString
Literal:status or %s(status)"status" or 'status'
Same object each timeYes (:a.equal?(:a) is true)No, unless frozen string literals are on
MutableNeverYes, unless frozen
ComparisonBy identity, fastBy content
Typical useHash keys, method names, enum-like valuesText and external data
Conversion:a.to_s gives "a""a".to_sym gives :a

Hash keys

ruby
user = { name: "Ada" }          # shorthand for { :name => "Ada" }
user[:name]                     # => "Ada"
user["name"]                    # => nil, a different key

parsed = JSON.parse('{"name":"Ada"}')                       # keys are strings
parsed["name"]                                              # => "Ada"
JSON.parse('{"name":"Ada"}', symbolize_names: true)[:name]  # => "Ada"

user.transform_keys(&:to_s)     # convert all keys to strings

In Rails, params and ActiveSupport::HashWithIndifferentAccess accept both, which hides the difference; plain Ruby hashes do not.

Strings that behave like symbols

With the magic comment # frozen_string_literal: true at the top of a file, identical string literals are frozen and may share one object, which removes most of the memory argument for symbols. Since Ruby 3.4, string literals in files without that comment are "chilled": modifying one still works but emits a deprecation warning when deprecation warnings are enabled.

Sources