The Splat* Operator’s Odd Abilities

David Chase
May 7, 2017 · 5 min read
splat (image credit: Corrie White)

I’m dedicating my first post to the splat operator, one of the weirder characters in the Ruby universe. The splat(*) operator is most commonly used to pass an unspecified number of arguments into a method, allowing for more flexible code. However, it has a few additional capabilities that allow for some interesting array manipulations.

Defining and Calling Methods

In the following example, it would appear that the method could only accept two parameters. However, the splat operator preceding the second argument will collect any additional arguments passed when the method is called and funnel them into the method as an array.

def suspense_creator(suspense, *sentences)
sentences.each do |sentence|
puts “#{sentence}#{suspense}”
suspense_creator(“…”, “It was sunny”, “The flowers were in bloom”, “It couldn't be a nicer day”)# It was sunny...
# The flowers were in bloom...
# It couldn't be a nicer day...

The first string passed will be captured in the “suspense” argument, while any additional values will be grouped together into an array and passed into the “sentences” argument.

The splat operator is not exclusively reserved for the last parameter. For example:

def drive_thru_uncertainty(warning, *items, regret)
items.each do |item|
puts "#{warning} #{item}?"
puts "#{regret}"
drive_thru_uncertainty("Are you sure you want to order", "chili cheese fries", "KFC's Double Down Chicken Sandwich", "a crave case", "...I've made a huge mistake.")# Are you sure you want to order chili cheese fries?
# Are you sure you want to order KFC's Double Down Chicken Sandwich?
# Are you sure you want to order a crave case?
# ...I've made a huge mistake.

When the method is called, Ruby will channel the first and last strings to the “warning” and “regret” arguments, respectively. Anything in between will be Hoovered up by the splat-infused “items” argument.

Ruby lets you utilize the splat operator when calling methods as well, which is useful if you have values stored in an array that you would like to pass in as arguments. Note that the number of elements in the array should match the number of method arguments.

numbers = [4, 6]def multiply(x, y)
puts x * y
#=> 24

Without including the splat operator in the method call, Ruby will throw an argument error IN YOUR FACE.


Array Manipulation and Mass Assignment

The splat operator also offers a couple of interesting functionalities when it comes to arrays. First, you can coerce objects into an array by preceding it with a splat.

meals = *"breakfast", "lunch", "dinner"
#=> ["breakfast", "lunch", "dinner"]
numbers_array = *(1..100)
#=> [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100]
hash_to_array = *{key, "value"}
#=> [[:key => "value"]]
nil = *nil
#=> []
array = *["a", "b", "c"]
#=> ["a", "b", "c"]

Note that it won’t nest an already existing array and it won’t work with nil. This property of the splat can provide a good way to ensure that the object you are dealing with is always an array.

You can also use the splat operator to efficiently flatten arrays:

seasons = ["spring", "summer", "fall"]four_seasons = [*seasons, "winter"]four_seasons
#=> ["spring", "summer", "fall", "winter]
flattened_array = [*["a", "b"], *["c", "d"]]
#=> ["a", "b", "c", "d"]

Finally, the splat operator lets you carve an array into separate pieces using mass assignment. Here we can isolate the first element from the rest by placing the splat operator on our “rest” argument:

array = ["a", "b", "c", "d", "e"]first, *rest = arrayfirst
#=> "a"
#=> ["b", "c", "d", "e"]

Similarly, we can siphon off the last element from an array by placing the splat on the “first” argument:

array = ["a", "b", "c", "d", "e"]*first, last = arrayfirst
#=> ["a", "b", "c", "d"]
#=> "e"

We can isolate both the first and last elements by placing the splat on the “middle” argument seen below:

array = ["a", "b", "c", "d", "e"]first, *middle, last = arrayfirst
#=> "a"
#=> ["b", "c", "d"]
#=> "e"

The Double Splat (**) Operator

The double splat is similar to the single splat in that it will take in additional arguments except it is explicitly looking for hashes to be passed.

def method(**hash)
puts hash
method(key1: "value1", key2: "value2")
#=> {:key1 => "value1", :key2 => "value2"}
#=> {}
method("I'm a string. This is not going to work.")
#=> ArgumentError: wrong number of arguments (given 1, expected 0)

If no hash is passed, the method will return an empty hash. If a non-hash value or nil is passed, Ruby will throw an argument error. In your face.


What if we combine a “regular” argument, a splat and a double splat? Let’s find out:

def argument_madness(regular, *splat, **double_splat)
[regular, splat, double_splat]
argument_madness("I'm alone", "I'm in a nested array", "Me too!", "Me three!", key1: "I'm a value", key2: "I'm also a value")#=> ["I'm alone",
["I'm in a nested array", "Me too!", "Me three!"],
{:key1=>"I'm a value", :key2=>"I'm also a value"}]

As shown above, the first value passed to the method will be encapsulated by the “regular” argument, while the rest of the non-hash values will be grouped together by the splat operator in an array. The key-value pairs will be grouped together in a hash by the double splat. The order here does matter, so you need to be careful where you are placing your hashes when calling the method.

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade