rubyruby-moduleruby-comparable

Where is Comparable <=> implemented?


I'm reading Comparable module.

And trying to see where Comparable module itself is implemented, but I can’t find it anywhere. I only see places where it gets added using include.

Isn't that the module should have its implementation provided elsewhere? So that you just do a plug and play by using include?

Or is that in the following code:

class Geeksforgeeks
      
# include comparable module
include Comparable
attr :name
      
    def <=>(other_name) # LineA
        name.length <=> other_name.name.length # LineB
    end
      
    def initialize(name)
        @name = name
    end
end

LineA: is something at the Geeksforgeeks class level.

LineB: is something at Integer (Length) level.

If that's the case then where is <=> written for Integers?

EDIT:

My code builds without include Comparable. I'm just not so sure what it means though:

class Geeksforgeeks
    
# does not include Comparable
attr :name
        
    def <=>(other_name) # LineA
        name.length <=> other_name.name.length # LineB
    end
        
    def initialize(name)
        @name = name
    end
end

jack = Geeksforgeeks.new('jack')
pete = Geeksforgeeks.new('pete')
alexander = Geeksforgeeks.new('Alexander')

def areSameGeeks(g1, g2)
    if g1 <=> g2
        puts 'equal'
    else 
        puts 'not equal'
    end
end

areSameGeeks(jack,pete) # equal
areSameGeeks(jack, jack) # equal
areSameGeeks(jack, alexander) # equal

Like why are all three, returning 'equal'?


Solution

  • An example might help to understand how Comparable works:

    module MyComparable
      def ==(other)
        (self <=> other) == 0
      end
    
      def <(other)
        (self <=> other) < 0
      end
    
      def >(other)
        (self <=> other) > 0
      end
    end
    

    The above module defines the methods ==, < and >. Their implementations rely on another method <=> which isn't defined by the module.

    To actually use the module's methods, the including class has to provide this <=> in a meaningful way, e.g.:

    class Foo
      include MyComparable   # <- this adds its instance methods to Foo
    
      attr_reader :name
    
      def initialize(name)
        @name = name
      end
    
      def <=>(other)
        name.length <=> other.name.length
      end
    end
    

    This gives us:

    Foo.new("abc") == Foo.new("123")  #=> true
    Foo.new("abc") == Foo.new("1234") #=> false
    Foo.new("abc") <  Foo.new("1234") #=> true
    

    == and < are from MyComparable, but it only works because of Foo#<=>.

    A similar approach is taken by Enumerable which requires an each method to be implemented by the including class.