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?
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.
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.
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.
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.
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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With