Ruby Scoping Bug?

class Foo
  def title
    "Oh hai."
  end

  def buggy
    puts title

    if false
      title = 'Oh noes!'
    end

    puts title
  end
end

Foo.new.buggy

This code outputs:

Oh hai.
nil

Isn’t it odd that the variable being created in an if-false block is still being created and set to nil? Hopefully this is fixed in Ruby 1.9.

22 Comments

  1. Oleg Andreev says:

    This is a feature, not a bug. Ruby knows when “a” is a method or a local variable only by lexer heuristics. When lexer encounters local variable assignment (a=, a||=) within the scope (e.g. method body; if-then-else blocks are not new scopes by design), it marks “a” as a local variable and you have no way to call a method “a” then.

    Sometimes this funny behavior is useful:
    http://oleganza.tumblr.com/post/57906287/ruby-local-variable-semantics

    In my practice i have never had a trouble with these semantics: i have small methods, thus little number of local variables, and well-chosen names for everything.

  2. Wow, interesting bug! I don’t have an explanation for it either, and was able to reproduce it in both Ruby 1.8.6 and 1.8.7. It’s good to know this issue exists, as I’m sure it could cause some debugging headaches… However, I generally try to avoid naming my local variables the same as my methods, because of the potential for confusion.

  3. Oleg is right, but it may seem surprising.

    See here for some more somewhat surprising results: http://pennysmalls.com/2007/10/01/why-ruby-is-not-my-favourite-programming-language/

  4. ste says:

    class Foo
    def title
    “Oh hai.”
    end

    def buggy
    puts title

    if false
    title = ‘Oh noes!’
    end

    puts title()
    end
    end

    Foo.new.buggy

    Oh hai.
    Oh hai.

    Like Oleg said, “if” does not introduce a new scope: at first “title” is resolved to a method invocation, then intepreter sees a variable assignment inside the _current_ scope, so from there on “title” is bound to a local variable. If for some reason you want to have both a variable and a method with the same name in your code, the least you can do is not fooling the interpreter :-)
    I think this “bug” is a very small price to pay to have uniform access.

  5. cies breijs says:

    anybody tested it with 1.9?

    i think this is one of the issues Matz pointed out he wants to get ‘rite’ in 1.9/2.0.

    _cies.

  6. Radarek says:

    Guys, everything is expected. If interpreter would decide that given name is local variable or method in runtime it could works even strangely. Consider this example:

    http://pastie.org/375282

    class Foo
    def title
    “Oh hai.”
    end

    def buggy
    puts title

    if rand(2) == 0
    title = ‘Oh noes!’
    end

    puts title
    end
    end

    Foo.new.buggy

    Depending on returned value by rand(2) it would use sometimes variable title and sometimes call a method. It would be very evil. Now you can be sure: it always use local variable (even if it will be set to nil).

    Another advantage of that behavior is that you IDE/editor can say during editing that given name is variable or method. Netbeans do that by make bold methods so looking at code you can see it clearly. It’s very important because one of frequent allegations that people saying is that it’s difficult to say looking on source code if something is method or variable, for example:

    def foo
    # many lines of code
    x = a + b # a and b could be variable of method
    end

    But we can for 100% say if something is method or variable. As far as I know Perl can’t do that (sometimes) and decide it on runtime. We should be thankful for that.

  7. Radarek says:

    “When lexer encounters local variable assignment (a=, a||=) within the scope (e.g. method body; if-then-else blocks are not new scopes by design), it marks “a” as a local variable and you have no way to call a method “a” then.”

    It’s not true. You can always use “()” to make explicit method call.

  8. Адам says:

    Актуальный блог, свежая инфа, почитываю

  9. Other variant is possible also

  10. facebok says:

    Always thought that your blog is one of the best in my bookmarks, and once again saw this

  11. Агния says:

    Привет, статья интересная и я тоже процитирую у себя в блоге

  12. Текст перспективный, помещу сайт в избранное.

  13. Hello. Watch Free NHL live P2P streaming. TVU, tvants, justin.tv, ustream.tv, sopcast, uusee, ppstream, etc.
    Watch NHL schedule, live streaming and much more.

  14. NHL Shop says:

    I wanted to thank you for this excellent read!! I definitely loved every little bit of it. I have you bookmarked your site to check out the latest stuff you post.

  15. Ryker says:

    You got numerous positive points there. I made a search on the issue and found nearly all peoples will agree with your blog.

  16. Have you ever considered adding more videos to your blog posts to keep the readers more entertained? I mean I just read through the entire article of yours and it was quite good but since I’m more of a visual learner,I found that to be more helpful well let me know how it turns out. Keep up the great works guys I’ve added you guys to my blogroll. This is a great article thanks for sharing this informative information.. I will visit your blog regularly for some latest post.

  17. Hi, I cant understand how to add your website with my rss reader. Can you Help me, plz

Leave a Reply