# Ruby Spaceship <=> Operator

Adhering to the law of trichotomy, the `<=>` operator (sometimes called the “Spaceship Operator”) works by comparing two elements and returning a `-1`, `0`, or `1`. While the original mathematical criteria applies to only real numbers, many programming languages implement the law of trichotomy as a general comparison between equivalent types.

## Basics

At first glance, the return value of the `<=>` operator can be a bit confusing. A simple way to remember the significance of these return values is to break an expression down from left to right:

### 1. `<` –> `-1`

if `a < b`, then `-1` is returned

### 2. `=` –> `0`

if `a = b`, then `0` is returned

### 3. `>` –> `1`

if `a > b`, then `1` is returned

Example:

``````> a = 3
> b = 5
> a <=> b
# => -1

> a = 3
> b = 3
> a <=> b
# => 0

> a = 10
> b = 3
> a <=> b
# => 1
``````

## Sorting

The `<=>` operator can be used alone for comparison or its contract honored within a block following the `sort` method.

By default, the `<=>` operator behaves as described above:

``````list = [8, 3, 1, 4, 0, 3]
list.sort { |a, b| a <=> b }
# => [0, 1, 3, 3, 4, 8]
``````

Following this pattern, it is easy to sort a list in reverse by swapping operand positions:

``````list = [8, 3, 1, 4, 0, 3]
list.sort { |a, b| b <=> a }
# => [8, 4, 3, 3, 1, 0]
``````

The `sort` method is extendable beyond explicit use of the `<=>` operator. A block passed to `sort` must only return either `-1`, `0`, or `1` for sorting to work effectively.

If the same list were to be ordered in odds then evens:

``````list = [8, 3, 1, 4, 0, 3]
list.sort { |a, _| a.odd? ? -1 : 1 }
# => [3, 3, 1, 4, 8, 0]
``````

Also, since `-1`, `0`, and `1` are simple integers, creating compound `<=>` blocks is possible. If the same list were to be sorted odds then evens, with all odd and even numbers sorted in ascending order, it might look like this:

``````list = [8, 3, 1, 4, 0, 3]
list.sort do |a, b|
if a.odd?
if b.odd?
# both are odd, default <=> behaviour is used
a <=> b
else
-1 # a < b
end
else # a is even
if b.even?
# both are even, default <=> behaviour is used
a <=> b
else
1 # a > b
end
end
end
# => [1, 3, 3, 0, 4, 8]
``````

Far from elegant, this code effectively sorts the array of numbers first by odds to evens and then in ascending order.

## Custom Methods

While thought of and generally referred to as an operator, `<=>` is actually a method. Defined originally on `Object`, any object has the opportunity to redefine this method to achieve custom sort behaviour.

An example class, `Node`, has a single attribute `value`:

``````class Node
attr_accessor :value
end
``````

By default, sorting an array of `Node` objects does not produce the desired result:

``````node1 = Node.new
node1.value = 20

node2 = Node.new
node2.value = 10

node3 = Node.new
node3.value = 30

list = [node1, node2, node3]
list.sort

# => ArgumentError: comparison of Node with Node failed
``````

However, with a custom `<=>` method:

``````class Node
attr_accessor :value

def <=>(other_node)
self.value <=> other_node.value
end
end

list = [node1, node2, node3]
list.sort
# => [#<Node: @value=10>, #<Node: @value=20>, #<Node: @value=30>]
``````

Boom! Custom sorting in the mix!

Admittedly, this same behaviour is possible with the built in `sort_by` method:

``````list = [node1, node2, node3]
list.sort_by(&:value)

# => [#<Node: @value=10>, #<Node: @value=20>, #<Node: @value=30>]
``````

But, what happens when the `Node` class wants to expose a sorting mechanism while removing its `value` method? In that case, the `sort_by` method would no longer be sufficient.

Defining a custom `<=>` method also allows objects to include the `Comparable` mixin effectively. The `Comparable` mixin provides the conventional comparison operators (`<`, `>`, `<=`, etc.).

``````class Node
include Comparable
attr_accessor :value

def <=>(other_node)
self.value <=> other_node.value
end
end

node1 = Node.new
node1.value = 200

node2 = Node.new
node2.value = 300

node1 > node2
# => false

node1 < node2
# => true

node3 = Node.new
node3.value = 250

node3.between?(node1, node2)
# => true
``````

The `Comparable` mixin provides very useful functionality that can easily turn a custom class into a sortable list element. As with most patterns in software, using the right tool at the right time is very important. It may not always be appropriate to write a custom comparison mechanism for a class, but when it is, the collaboration of `<=>` and the `Comparable` mixin is worth evaluating.