Search code examples
ruby

Ruby: Make a global method that checks my class's type (Pair)


I am trying to create a global boolean method that checks if a variable is of type Pair (my own customized class). However, when I try to run it, I get the error

Project4.rb:83:in `<main>': private method `pair?' called for #<Pair:0x00000212de6861e8 @value1=5, @value2=7> (NoMethodError)

puts a.pair?
      ^^^^^^ 

What do I do? My code is below.

#Pair (class): Takes two values and creates a list from them. Executing the code should return a list without displaying any output.
#   Returns: A list of at least two elements.
#   Parameters:
#       value1 (any class, including pair) - a value to insert into list.
#       value2 (any class, including pair) - another value to insert into list.
#
#Declare class `Pair`
class Pair
    #Initialize
    def initialize(value1, value2)
        @value1 = value1
        @value2 = value2
    end

    #Method: car - return the car of the pair.
    def car
        return @value1
    end
    
    #Method: cdr - return the cdr of the pair.
    def cdr
        return @value2
    end
    
    #Method: to_s - Return string representation of the pair.
    # def to_s
    #     "(#{@value1} . #{@value2})" 
    # end

    #Method: list? - returns true if pair is a valid list and false otherwise.
    def list?
        #If value2 is a pair...
        if (@value2.class == Pair)
            #...Recursively call the list? method again with the cdr.
            cdr.list? #Recursion
        else
            #If value2 is a null (nil) value, then it is a list.
            if (@value2 == nil)
                return true
            else
                return false
            end
        end
    end

    #Method: count - If the pair is a list, return the number of items in the top level of the list. Return false otherwise.

    #Method: append(other) - If the pair is a list, append should return a new list consisting of `other`` appended to the original list. 

    #Method: null? -  returns true only if the pair is an empty list.
    def null?

    end

    #Implement a null/empty list value.
    def self.null
        nil
    end

end

#Implement a global `pair?` method. MUST NOT TAKE PARAMETERS!
def pair?
    if (is_a? Pair)
        return true
    else
        return false
    end
end

Please reply at your earliest conveniene.


Solution

  • A global method doesn't require a receiver and can be called in functional form, for example puts or loop. Your method however does require a receiver because it's based on is_a?.

    To turn your method into a working global method, you'd need to pass the object:

    def pair?(obj)
      obj.is_a?(Pair)
    end
    

    MUST NOT TAKE PARAMETERS!

    Okay, noted. You probably don't want a global method in the first place but an instance method of Object:

    class Object
      def pair?
        is_a?(Pair)
      end
    end
    

    This is "global" in the sense that you can call it on any object.

    You can even omit the explicit type check by utilizing inheritance. Implement a Object#pair? method which provides a default value of false for all objects:

    class Object
      def pair?
        false
      end
    end
    

    and override it in your Pair class to return true:

    class Pair
      def pair?
        true
      end
    end
    

    Example:

    Object.new.pair? #=> false
    "a string".pair? #=> false
    
    Pair.new.pair?   #=> true
    

    This is exactly how nil? works, see the implementation for Object#nil? and NilClass#nil?.

    Keep in mind that adding methods to Object might result in cluttered classes as those methods become available to all objects. It's great for exploring OOP principles but you shouldn't do it in general.