Using splats to build up and tear apart arrays in Ruby

The humble splat operator (*) is one of those features of Ruby that just gets more interesting the more you look at it. In this post we'll talk about how you can construct and manipulate arrays with splats.

One of the things that I love about Ruby is the depth of its features. You may use an operator, but do a little digging and you'll find that you've only been scratching the surface of what it's capable of. The humble splat operator (* and **) is a great example.

You've probably used splats for "catch-all" arguments. And that's all that most people use them for.

def go(x, *args)
  puts args.inspect
end

go("a", "b", "c")

If you are using the newfangled keyword argument syntax, use a double splat like so:

def go(**params)
  puts params.inspect
end

go(x: 100, y: 200)

This is useful, but you can use splats for a lot more. Let's dive in!

Using an array to pass multiple arguments

Not only can you use splats when defining methods, but you can also use them when calling methods. They let you pass an array into a function expecting multiple arguments. The first item in the array becomes the first argument, the second item becomes the second argument and so on.

def go(x, y)
end

point = [12, 10]
go(*point)

And don't forget that you can use a double splat for new style keyword arguments:

def go(x:, y:)
end

point = { x: 100, y: 200 }
go(**point)

The splat doesn't have to go at the end

While it's common to put your splatted arguments at the end of the argument list, there is no law requiring it.

You can put the splat anywhere in the argument list.

def go(x, *args, y)
  puts x # => 1
  puts y # => 5
  puts args.inspect # => [2,3,4]
end

go(1, 2, 3, 4, 5)

Array Destructuring

All of these tricks with arguments are just a special case of array destructuring.

In case you aren't familiar with the term "array destructuring," it simply means to break an array down into individual items. It looks like this:

a, b = [1, 2]
puts a
# 1
puts b
# 2

This works well but it can be a pain to have to specify a variable to hold every single item in the array. The splat operator gets around this - acting essentially like a wildcard. Lets take a look at a few examples.

Popping the first item from an array

Occasionally it's useful to be able to pop the first item off of an array without altering the original array. That's what this example does.

first, *remainder = [1, 2, 3, 4, 5]
first
# => 1
remainder
# => [2, 3, 4, 5]

If you just wanted the first item but not the rest of the array, you can use the syntax:

first, * = [1, 2, 3, 4, 5]
first
# => 1

Popping the last item

To pull the item off of the end of the array instead of the beginning, just stick the splat at the beginning like so:

*prefix, last = [1, 2, 3, 4, 5]
last
# => 5
prefix
# => [1, 2, 3, 4]

Again, if we don't want a specific variable, we don't have to assign it:

Get the first and last n items of an array

If you put the splat operator in the middle, you can pull an arbitrary number of items off of each end of the array.

first, *, last =  [1, 2, 3, 4, 5]
first
# => 1
last
# => 5

Limitations

When using the splat operator in array destructuring, you still have to specify the position of array items with respect to the beginning and end of the array. So it's not the best tool for extracting items from the middle of a long array.

Also, I can't seem to find any cool tricks using the double-splat (**) operator to mess with hashes. Lame!

Constructing arrays

The splat operator is useful not only for destructuring arrays but also for constructing them.

In the following example, we use splat to join two arrays.

[*[1,2], *[3,4]]
=> [1, 2, 3, 4]

This is the equivalent of [[1, 2], [3,4]].flatten.

If that were the end of the story, it wouldn't be very useful. But splat has another peculiar ability. It can intelligently coerce objects into arrays.

# Usually `*thing` wraps `thing` in an array
x = *"hi mom"
# => ["hi mom"]

# ...unless it's nil
x = *nil
# => []

# Arrays are passed through unchanged
x = *[1,2,3]
# => [1, 2, 3]

# But hashes are converted to arrays
x = *{a: 1}
# => [[:a, 1]]

This gives us a tool for building arrays without having to do a ton of manual type coercion.

For example, imagine you're collecting an array of strings for some configuration system. Normally you'd want to:

  • Check if the array exists, and initialize it if not
  • Respond intelligently if someone tries to add an array of strings, not just a single string

The splat operator gives us this for free:

# Your configuration hash may or may not have
# an existing :ignore array. 
config = { }

# The callback function might return an array
# or it might return a single item. 

def add_ignores
  "scoundrels" # could also be an array like ["scoundrels", "cads", "ne'er-do-wells"]
end

# This is where the magic happens. No matter what you 
# start with you get an array of things to ignore. 
config[:ignore] = [*config[:ignore], *add_ignores()]

That's it

I hope it's obvious that you probably shouldn't go rewrite all of your existing array-manipulation code to use splats. They're not always the right tool, and they can make code hard to read when used to frequently.

However, sometimes an array splat trick is exactly what you need. I hope, when that time comes, you'll try one out. :)

What to do next:
  1. Try Honeybadger for FREE
    Honeybadger helps you find and fix errors before your users can even report them. Get set up in minutes and check monitoring off your to-do list.
    Start free trial
    Easy 5-minute setup — No credit card required
  2. Get the Honeybadger newsletter
    Each month we share news, best practices, and stories from the DevOps & monitoring community—exclusively for developers like you.
    author photo

    Starr Horne

    Starr Horne is a Rubyist and Chief JavaScripter at Honeybadger.io. When she's not neck-deep in other people's bugs, she enjoys making furniture with traditional hand-tools, reading history and brewing beer in her garage in Seattle.

    More articles by Starr Horne
    Stop wasting time manually checking logs for errors!

    Try the only application health monitoring tool that allows you to track application errors, uptime, and cron jobs in one simple platform.

    • Know when critical errors occur, and which customers are affected.
    • Respond instantly when your systems go down.
    • Improve the health of your systems over time.
    • Fix problems before your customers can report them!

    As developers ourselves, we hated wasting time tracking down errors—so we built the system we always wanted.

    Honeybadger tracks everything you need and nothing you don't, creating one simple solution to keep your application running and error free so you can do what you do best—release new code. Try it free and see for yourself.

    Start free trial
    Simple 5-minute setup — No credit card required

    Learn more

    "We've looked at a lot of error management systems. Honeybadger is head and shoulders above the rest and somehow gets better with every new release."
    — Michael Smith, Cofounder & CTO of YvesBlue

    Honeybadger is trusted by top companies like:

    “Everyone is in love with Honeybadger ... the UI is spot on.”
    Molly Struve, Sr. Site Reliability Engineer, Netflix
    Start free trial