First and Rest in Ruby

A common pattern when doing functional-style programming is to split a list into first and rest components, otherwise known as head and tail (or car and cdr in Lisp). first is the first item in the list, or nil if the list is empty. rest is a zero or more-length list containing the remaining elements in the original list.

For instance, here’s a recursive reimplementation of Ruby’s Array#join method which splits the joined list into first and rest:

def rec_join(list, delim)
  case list.size
  when 0 then ""
  when 1 then list.first.to_s
  else list.first.to_s + delim + rec_join(list[1..-1], delim)
  end
end

rec_join([:foo, :bar, :baz], ', ') # => "foo, bar, baz"

In this example we used list.first to get the first element, and list[1..-1] to get the rest. But is this a robust way to split an array into head and tail components? Let’s see:

zero = []
one  = [0]
many = [0,1,2,3,4]

first, rest = zero.first, zero[1..-1]
first                           # => nil
rest                            # => nil
first, rest = one.first, one[1..-1]
first                           # => 0
rest                            # => []
first, rest = many.first, many[1..-1]
first                           # => 0
rest                            # => [1, 2, 3, 4]

Hmmm. We said that rest should always be a list with zero or most elements; but when given an empty list to start with, this technique gives us nil as the tail of the list. It’s also a bit ugly. Let’s see if we can do better.

first, rest = *zero
first                           # => nil
rest                            # => nil
first, rest = *one    
first                           # => 0
rest                            # => nil
first, rest = *many        
first                           # => 0
rest                            # => 1

Now we’re using the splat operator to break the source list into it’s parts. The code is much more concise, but the results are very wrong. In this version rest is never a list!

However, a slight refinement and we have exactly what we want:

first, *rest = *zero
first                           # => nil
rest                            # => []
first, *rest = *one    
first                           # => 0
rest                            # => []
first, *rest = *many        
first                           # => 0
rest                            # => [1, 2, 3, 4]

Here we’ve added a splat operator to the left side of the variable assignment as well, telling Ruby to collect all remaining values into an Array assigned to the rest variable. This version works exactly as we intended, and is still concise. I first saw this technique used in the DataMapper codebase, and it’s the most elegant way I’ve come across to break a Ruby Enumerable object into first and rest components.

5 comments

  1. I was reading the Twitter post about first and rest and I immediately thought about the splat operator as Ruby’s idiomatic head/tail version. Having learnt programming with a function language in college (OCaml), it seems very natural to do things this way in Ruby. The one bit I really crave for though is proper pattern matching.

  2. This post is 3 years old so times may’ve changed, but I’d like to point out that you don’t need the splat on the right hand side. first, *rest = [1, 2, 3] is sufficient.

Leave a Reply

Your email address will not be published. Required fields are marked *