Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Ruby Koans: Why convert list of symbols to strings

Tags:

ruby

I'm referring to this test in about_symbols.rb in Ruby Koans https://github.com/edgecase/ruby_koans/blob/master/src/about_symbols.rb#L26

def test_method_names_become_symbols   symbols_as_strings = Symbol.all_symbols.map { |x| x.to_s }   assert_equal true, symbols_as_strings.include?("test_method_names_become_symbols") end     # THINK ABOUT IT:   #   # Why do we convert the list of symbols to strings and then compare   # against the string value rather than against symbols? 

Why exactly do we have to convert that list into strings first?

like image 510
codercode Avatar asked Jan 13 '11 22:01

codercode


People also ask

Why do we convert the list of symbols to strings and then compare?

Isaac, because of the issue identified, which is that specifying :test_method_names_become_symbols in the comparison will create it, so the comparison will always be true. By converting all_symbols to strings and comparing strings, we can distinguish whether the symbol existed prior to the comparison.

How does symbol differ from string in Ruby?

There are two main differences between String and Symbol in Ruby. String is mutable and Symbol is not: Because the String is mutable, it can be change in somewhere and can lead to the result is not correct. Symbol is immutable.

Why is it not a good idea to dynamically create a lot of symbols?

If you dynamically create lots of symbols, you are allocating a lot of memory that can't be freed until your program ends. You should only dynamically create symbols (using string.

How do I convert a string to a symbol in Ruby?

Ruby supports both Strings & Symbols. String being mutable & Symbols being immutable cater to different needs. We can convert String to Symbol & Symbol to String at any time. To convert a string to a symbol, we can use intern method or to_sym method which are aliases to each other.


2 Answers

This has to do with how symbols work. For each symbol, only one of it actually exists. Behind the scenes, a symbol is just a number referred to by a name (starting with a colon). Thus, when comparing the equality of two symbols, you're comparing object identity and not the content of the identifier that refers to this symbol.

If you were to do the simple test :test == "test", it will be false. So, if you were to gather all of the symbols defined thus far into an array, you would need to convert them to strings first before comparing them. You can't do this the opposite way (convert the string you want to compare into a symbol first) because doing that would create the single instance of that symbol and "pollute" your list with the symbol you're testing for existence.

Hope that helps. This is a bit of an odd one, because you have to test for the presence of a symbol without accidentally creating that symbol during the test. You usually don't see code like that.

like image 113
AboutRuby Avatar answered Oct 02 '22 11:10

AboutRuby


Because if you do:

assert_equal true, all_symbols.include?(:test_method_names_become_symbols) 

It may (depending on your ruby implementation) automatically be true, because :test_method_names_become_symbols creates the symbol. See this bug report.

like image 39
Andrew Grimm Avatar answered Oct 02 '22 12:10

Andrew Grimm