0

While stepping through code today, I noticed something unexpected. This statement:

if Object.respond_to? :hello && Object.hello #stuff

gives an undefined method error. But why? Obviously hello is not a valid method of Object, however given the short-circuit evaluation, shouldn't Object.hello be ignored whenever Object.respond_to? :hello is false?

I noticed this while playing with Authlogic, trying to figure out exactly why the UserSession class must define persisted? in Rails 3.

Thanks

TheTFo
  • 741
  • 2
  • 8
  • 25

4 Answers4

4

The lack of parentheses is leading to a precedence issue:

>> Object.respond_to? :hello && Object.hello
NoMethodError: undefined method `hello' for Object:Class
    from (irb):2
    from /Users/john/.rvm/rubies/ruby-1.9.2-p136/bin/irb:16:in `<main>'
>> Object.respond_to?(:hello) && Object.hello
=> false
John
  • 29,546
  • 11
  • 78
  • 79
  • rails3/gems/actionpack-3.0.3/lib/action_view/helpers/form_helper.rb line 329 gives a NoMethodFound error unless you define a persisted? method in your UserSession class in rails 3, this is a common, known issue. But the code looks like this: if object.respond_to?(:persisted?) && object.persisted? Why does this fail, then? – TheTFo Feb 23 '11 at 05:20
  • In Authlogic that is... Sorry. – TheTFo Feb 23 '11 at 05:26
2

You have a precedence problem, the logical conjunction (&&) has a higher precedence than the method call so your example is executed like this:

if Object.respond_to?(:hello && Object.hello)

not like this:

if Object.respond_to?(:hello) && Object.hello

which is what you're assuming.

mu is too short
  • 426,620
  • 70
  • 833
  • 800
1

I believe you are running into an evaluation order problem. Consider the following:

Object.respond_to? :hello && true 
Robert Horvick
  • 3,966
  • 21
  • 18
-3

If you are checking the condition of something with an if statement you are looking for a boolean response. Object.hello doesn't return false because the method doesn't exist. Your check of:

Object.respond_to? :hello

Is checking for that response though. There shouldn't be any reason, in my option for the second Object.hello.

Tim Knight
  • 8,346
  • 4
  • 33
  • 32
  • I'm not sure I understand what you're saying here. The idea of my line of code is to say something along the lines of "If method hello exists for Object, execute it". However, it doesn't exist, respond_to returns false, therefore Object.hello should NOT be executed, and should NOT give me an error saying the method doesn't exist. This is the entire point of respond_to, isn't it? I've seen this cause at least one problem in rails. – TheTFo Feb 23 '11 at 05:10
  • BTW, I'm using method respond_to?, not response_to? – TheTFo Feb 23 '11 at 05:12
  • I apologize for the spelling error - it was late. Because of the lack of parentheses I was seeing this as Object.respond_to?(:hello) && Object.hello = which is why I was saying you were going to be getting a true/false response from Object.hello. As the accepted answer stated it was a precedence issue that I was miss reading. Glad you found your response. – Tim Knight Feb 23 '11 at 19:41