Ruby Single and Double Splat Operators
In this example, calling
*arr spreads out the array
arr elements and pass its values to the function as positional arguments in the order it was given.
Note that if the array
arr contains more values than the positional arguments (2), it will error (try passing
arr = ["1", "2", "3"] ). Similarly, if you pass fewer arguments, you will get an error. The number of arguments passed must match the number of positional arguments accepted by the function (considering the arguments with a default value).
Single Splat operator as an argument in the function's definition
We have seen how we can use the Splat operator as a value, but we can also use it as an argument in the function definition. See the following example:
arg_1 is an argument that uses the splat operator, meaning that the positional arguments are the elements of the array
arg_1 . Hence, you can pass 0 or more positional arguments to the function.
It doesn't necessarily need to be the last argument. It can be in the middle of the function as the following example shows.
Double Splat operator in a function
This operator is very similar to the Single operator, but it's for Hashes (and kwargs).
Double Splat operator when calling a function
Two important things to keep in mind:
- The Hash must have precisely the same keys.
- The Hash must have the keys as symbols, not strings. Read this issue if you are curious to see why it doesn't use Strings.
Double Splat operator as an argument in the function's definition:
The function accepts 0 or more kwargs that are part of the
hash. A difference with the Single Splat operator that can be in any position, the Double splat argument must be the last in the argument list.
You might have wondered what's the difference between using the Splat
** Vs just a Hash variable in a function definition? Well, there are a few differences:
- The Double Splat is optional. You don't need to pass a value to the function.
- The Double Splat cannot have a default value, while the simple Hash can. The default value of the Double Splat is implicitly the empty Hash (
- If there are default values in positional arguments, the results could differ. See the following example:
Combining different types of arguments
You can combine single and double Splat operators as long as the Double Splat is the last argument and the number of arguments required is satisfied. See this example:
I've seen different bugs in production related to this operator, and all of them have mostly the exact cause: The sizes of arguments passed are different than the size required. This affects double and single operators.
Let's see an example. Take some time to read the following piece of code, and think about why this code is terrible before reading the reason below.
Imagine that we have an
Post linked to the table
posts containing three columns
PostSchema is a wrapper of the
Post class. It has a constructor that accepts the exact three attributes that the's table has.
Service has a method that receives a
post_id and looks up the table to find the post. If a post is found, it gets its attributes as a symbolized Hash and assigns them to the
attributes variable. Then it creates a
PostSchema using the double Splat with the
attributes variable. Finally, we print out the
Have you noticed anything wrong with this code? If not, take some time to read the
What happens if I change the schema of the
posts table? For example, let's add a new column
created_at to the
💥💥💥💥💥 Boom! The test now fails!. The reason is that the Splat operator now passes a new argument
PostSchema 'constructor doesn't support.
This is a corner case, but definitely cases like this happen!. Other bugs might be caused by different factors, such as using the double Splat with the keys as strings, but I haven't seen many.
The splat operator is beneficial, and I suggest using it. However, you should be careful when using it within functions. Mainly, make sure that the function satisfies the size of the arguments passed. Additionally, pay extra attention when there are default values, and ensure the keys are symbols if you use the double Splat as an argument value.