Search code examples
rubytypeerroroperator-precedence

Parens required or Ruby says: TypeError (class or module required) ... why?


I'm trying this in irb, Ruby version 3:

3.0.0 :001 > num = 42
 => 42 
3.0.0 :002 > num.is_a?(Integer) && num > 10
 => true 
3.0.0 :003 > num.is_a? Integer && num > 10
Traceback (most recent call last):
        5: from /Users/kai/.rvm/rubies/ruby-3.0.0/bin/irb:23:in `<main>'
        4: from /Users/kai/.rvm/rubies/ruby-3.0.0/bin/irb:23:in `load'
        3: from /Users/kai/.rvm/rubies/ruby-3.0.0/lib/ruby/gems/3.0.0/gems/irb-1.3.0/exe/irb:11:in `<top (required)>'
        2: from (irb):3:in `<main>'
        1: from (irb):3:in `is_a?'
TypeError (class or module required)

Why do I need the parentheses here:

v.is_a?(Integer)

?

How does the operator precedence work?

And why does Ruby generate such an arcane error message in this scenario?

With some digging I find the question answered previously here: Ruby 'is_a?' class or module required (TypeError)

and the fundamental issue addressed here: What's the precedence of method calls with and without parentheses?

which reference the official Ruby documentation: https://ruby-doc.org/core-3.0.0/doc/syntax/precedence_rdoc.html

But I don't feel all my questions are answered. Anyone care to wrap all of this up cleanly?


Solution

  • Why do I need the parentheses here:

    v.is_a?(Integer)

    You need the parenthesis to specify what you are passing to the is_a? method. Without them, Ruby evaluates the entire Integer && num > 10 expression and passes that to the method.

    How does the operator precedence work?

    is_a? isn't an operator, so there's no precedence for it to follow. Expressions are evaluated before being passed to methods, that's all that's happening.

    And why does Ruby generate such an arcane error message in this scenario?

    Ruby is evaluating the expression Integer && num > 10 which gives true. This value is then being passed to num.is_a?. is_a? then gives a TypeError as it expects a class or module, not a boolean.