Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Ruby Koan: Constants become symbols

Tags:

symbols

ruby

In the about_symbols.rb Ruby Koan (https://github.com/edgecase/ruby_koans), I have the following code:

    RubyConstant = "What is the sound of one hand clapping?"
    def test_constants_become_symbols
      all_symbols = Symbol.all_symbols

      assert_equal true, all_symbols.include?(:"nonexistent")

      assert_equal true, all_symbols.include?(:"What is the sound of one hand clapping?")
      assert_equal true, all_symbols.include?("What is the sound of one hand clapping?".to_sym)
    end

As is, the test passes.

Three questions:

  1. Why does the first assert pass? :"nonexistent" should not be included in all_symbols but it is included so I must be misunderstanding something.

  2. When I comment out the second assert, the test fails because "What is the sound of one hand clapping?".to_sym is not included in all_symbols whereas :"What is the sound of one hand clapping?" is included. Since they are equivalent, why does the last assert fail? Also, why does it pass when the second assert is not commented out? (Why does the second assert have any effect on the third assert?)

  3. To my knowledge, the point of this Ruby Koan was to demonstrate that constants become symbols (at least, that's what I'm inferring from the method name). Since RubyConstant is a constant with the value "What is the sound of one hand clapping?", why isn't "What is the sound of one hand clapping?".to_sym included in the list of symbols? The only explanation that I can think of is that, contrary to the method name, constants do not in fact become symbols.

Thanks for your help!

like image 935
dskang Avatar asked Mar 18 '11 23:03

dskang


2 Answers

hoha has it right but I'll try to expand and clarify a bit.

The interpreter will create the :nonexistent symbol when it parses test_constants_become_symbols. Then, when you run it, Symbol.all_symbols is called to get a list of all known symbols and :nonexistent is in the list. Also note that the double quotes on "nonexistent" are a syntax issue rather than an internal representation issue so :nonexistent and :"nonexistent" are the same thing.

If you comment out this one:

  assert_equal true, all_symbols.include?(:"What is the sound of one hand clapping?")

then the :"What is the sound of one hand clapping?" symbol will not be seen by the parser and so it won't be in the all_symbols array. The .to_sym method call on the following line is executed when test_constants_become_symbols is executed; so, the :"What is the sound of one hand clapping?" symbol is created after you get your all_symbols and this will fail:

  assert_equal true, all_symbols.include?("What is the sound of one hand clapping?".to_sym)

If you execute test_constants_become_symbols again in the same interpreter instance (with the second assert_equal still commented out) then both uncommented assert_equal calls will pass as the first run through test_constants_become_symbols will create the :"What is the sound of one hand clapping?" and the second Symbol.all_symbols will include it in the returned array.

Running your code in irb without wrapping it in a def might help you see what's going on.

like image 142
mu is too short Avatar answered Nov 15 '22 21:11

mu is too short


I'm not a Ruby guru but it looks like interpreter created this symbols during def expression evaluation. That's why these symbols are already there when you call Symbol.all_symbols. Third assert fails with second one being commented out because "string".to_sym creates symbol during methods execution i.e. after you got available symbols with all_symbols = Symbol.all_symbols.

like image 41
hoha Avatar answered Nov 15 '22 21:11

hoha