Recently I got bitten by defined?. Here’s the gotcha (the condition always passes and never goes into else…):

if defined? MyString && obj.instance_of?(MyString)
  # ...
else
  # ...
end

It turned out to be operator precendence (&& has higher precedence) 1.

obj = 'str'

defined? String                                  # => "constant"
defined? String && obj.instance_of?(String)      # => "expression"
defined?(String) && obj.instance_of?(String)     # => true

# MyString is not defined yet

defined? MyString                                # => nil
defined? MyString && obj.instance_of?(MyString)  # => "expression"
defined?(MyString) && obj.instance_of?(MyString) # => false

The original condition is actually equal to defined?(MyString && obj.instance_of?(MyString)). According to defined?, the expression given to defined? is not executed, which means MyString && obj.instance_of?(MyString) is always an "expression".

That’s the price for not memberizing the operator precendence table… However, since defined? has such low precendence, I guess it’s easier to just always add parenthesis.

Recent Posts