So, what is a symbol? According Ruby-doc,
Symbol objects represent names and some strings inside the Ruby interpreter. They are generated using the :name and :"string" literals syntax, and by the various to_sym methods. The same Symbol object will be created for a given name or string for the duration of a program‘s execution, regardless of the context or meaning of that name. Thus if Fred is a constant in one context, a method in another, and a class in a third, the symbol :Fred will be the same object in all three contexts.
What that means are:
- If you prefix a string or an legal Ruby name/identifier with a colon, it becomes a symbol.
- x = :"Matt" # x.class is a Symbol
- x.to_s() # "Matt"
- y = :userId # y.class is a Symbol
- y.to_s() # "userId"
- A symbol is an instance of Symbol class. If you runs Symbol.public_methods(false), irb will return 3 methods: ["superclass", "allocate", "all_symbols"]. all_symbols() method returns a table of symbols currently bound by runtime Ruby.
- Symbols are not strings because Symbol and String are 2 different classes. You cannot therefore do the following:
- Assign :user = "Sam" # syntax error, unexpected '=', expecting $end
- The correct way to assign a symbol is user = :"Sam"
- Invoke String's method :user.size() # NoMethodError: undefined method `size' for user:Symbol
- Correct way to get size of User symbol's value is :user.to_s().size()
- Symbol's value, a string, is obtained via via Symbol#to_s() or Symbol#id2name() methods. Vice versa, a string can be converted to Symbol via String#to_sym() or String#intern().
- Symbol is immutable so unlike String, you cannot modify a string once assigned.
- user.to_s()[0] = "K" # changing first character of 'Sam' will not affect user. Afterward, user.to_s() is still "Matt"
- Bonus: you can make a string/array object immutable via freeze() method. Vice versa, unfreeze() will allow string/array object to be editable.
Fine, you start to get impatient. Then tell me why and where you want to use symbol?
- Symbol as a key in Hash's key instead of string. Instead of having to refer to "id" string whenever rec["id"] is called, a good engineer would at least define a constant like static const String ID = "id in Java and always refer to rec[ID] instead. Ruby symbol does exactly that.
- rec = { id => :"101"; name => :"Matt Burnes"; email => :"mburnes@mclub.org" } # rec.class returns Hash
- p rec[:id] # "101"
- Save memory when replace a large number of identical strings. Since symbol id is a reference to a same identical "id", you reuse same memory for identical "id" every time "id" string is referred. I wish Ruby could be as smart as Java where it figures out if same literal string "id" is instantiated, any time it encounters same string, it will just reference it.
- id.object_id # returns 303408
- "id".object_id # 23700936
- "id".object_id # 23689692 (new object)
- "id".object_id # 23485564 (new object)
- id.object_id # still returns 303408
Conclusion
- Symbol is immutable.
- Symbol is not a string.
- Symbol is favored over String when same string is referenced repeatedly to save memory.
No comments:
Post a Comment