/compare/ruby/symbol-vs-string
Ruby symbol vs string: :name vs "name"
- 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
| Symbol | String | |
|---|---|---|
| Literal | :status or %s(status) | "status" or 'status' |
| Same object each time | Yes (:a.equal?(:a) is true) | No, unless frozen string literals are on |
| Mutable | Never | Yes, unless frozen |
| Comparison | By identity, fast | By content |
| Typical use | Hash keys, method names, enum-like values | Text and external data |
| Conversion | :a.to_s gives "a" | "a".to_sym gives :a |
Hash keys
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 stringsIn 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.