I am new to Ruby. Can someone kindly explain how the <=> method works in the following program. How is the 'other' parameter being used below?
class Age
attr_reader :value
def initialize(value)
@value = value
end
def <=> (other) # What is actually happening here...
self.value <=> other.value # ..and here?
end
end
a = Age.new(7)
b = Age.new(3)
c = Age.new(9)
d = [a, b, c]
puts d.sort
Let's start with d.sort
. d
is an array, so you should read about Array#sort
. The documentation says that sorting "will be done using the <=>
operator". That means when sorting the array it will repeatedly evaluate x <=> y
where x
and y
are different elements of d
, in order to determine which elements are bigger/smaller.
Operators in Ruby are a little tricky, because they're actually method calls in disguise. x <=> y
is just a different way of writing x.<=>(y)
. That is, x
has a method named <=>
which is being passed y
as an argument. Since the elements of d
are instances of the Age
class, Age
needs to define the instance method <=>
. So when you see def <=> (other)
, this is really no different from a normal method definition (def foo(other)
) but with a different method name.
Now that we're defining <=>
for Age
instances, what should the method actually do? Well each Age
object stores a @value
, so intuitively Age#<=>
should compare the @value
s. That's what self.value <=> other.value
does. This works because value
returns a Fixnum
, and luckily Fixnum#<=>
is built into Ruby to do the proper comparison.
For an example of what's going on behind the scenes, we can try sorting arrays containing values that we don't know how to compare:
[Age.new(3), 4].sort
# NoMethodError: undefined method `value' for 4:Fixnum
[4, Age.new(3)].sort
# ArgumentError: comparison of Fixnum with Age failed
This shows how sorting different types leads to different <=>
methods being called.