Destructuring in Ruby
Ridhwana Khan
Posted on August 3, 2022
Destructuring refers to the process of unpacking a small part of something from the main part. In Ruby, we use destructuring to conveniently extract multiple values from data stored in Arrays or Hashes. It provides a way for us to group or ungroup data and assign them to variables where needed.
In this article we’re going to discuss destructuring for assignments, arrays and keyword args. We’ll also touch on why you would utilize destructuring.
The most straightforward form of destructuring is through multiple assignments. This form of destructuring assigns the variables on the left to the values on the right in the order that they are provided.
As an example:
a, b, c = 1, 2, 3
a => 1
b => 2
c => 3
In the above example the variables on the left are assigned to the values on the right. If we have a mismatch between the number of variables ready for assignment on the left and the number of values on the right then some of the variables will remain unassigned like below:
a, b, c, d = 1, 2, 3
a => 1
b => 2
c => 3
d => undefined local variable or method `d' for main:Object
```
If we have a mismatch in the number of values on the left, with fewer variables to assign to them, then some of the values will remain unassigned like below:
```ruby
a, b, c = 1, 2, 3, 4
a => 1
b => 2
c => 3
```
More complex destructuring can be done using an operator in Ruby called the the splat (*) operator. Splat performs different operations depending on how it is used, let’s discuss how splat works.
## Slurp/Collect
When the splat operator appears on the left hand side of an assignment then we can refer to the operation as slurp or collect. Slurping takes a variable number of values and collects it into an array.
The example below with a *slurp on a variable at the end* will collect the rest of the values (into an array) that have not been assigned to the first two variables:
```ruby
a, b, *c = 1, 2, 3, 4
a => 1
b => 2
c => [3, 4]
```
Splat is pretty smart - it can slurp up the “rest” of the values depending where the splat operator is positioned. Let’s look at some more examples.
```ruby
a, *b, c = 1, 2, 3, 4
a => 1
b => [2, 3]
c => 4
```
A splat operator *somewhere in the middle* will get the “rest” of the values once the other non-splatted variables are assigned. In this case, `a` gets assigned to the first value, then `c` gets assigned to the last value and `b` gets assigned the remainder of the values in the form of an array.
Now, think about what you would expect a *slurp operator on a variable at the start* of the assignment to yield?
```ruby
*a, b, c = 1, 2, 3, 4
```
Well, we’d look at the non splatted values first and work our way backwards - `c` will take the value of 4, `b` will take the value of 3 and `a` would collect the “rest” of the values into an array i.e. `[1, 2]`. Does that make sense to you?
Just like above, an array can also be destructured into multiple parts and assigned to variables.
```ruby
a, *b, c = [1, 2, 3, 4, 5]
a => 1
b => [2, 3, 4]
c => 5
```
## Split
Up until now we talked about a splat on the left hand side of the assignment which slurps or collects up the values on the right hand side. How does it then work when the splat operator (*) is on the right hand side? It will split up the array into individual components.
```ruby
list = [2, 3, 4]
a, b, c = 1, *list
```
Destructuring on the right hand side allows us to split the collection into a list of values being assigned.
So in the case above the splat on `*list` will change the statement into:
```ruby
a, b, c = 1, 2, 3, 4
```
and so the assignments happen as per usual:
```ruby
a => 1
b => 2
c => 3
```
Let’s look at a more complex example - what if we had to split on the right side of the assignment and slurp up values on the left side, how would that work?
## Slurp and Split
```ruby
array = [2, 3, 4, 5]
a, *b, c = 1, *array
```
You’re already equipped with the tools for dealing with them separately so let’s apply that knowledge.
First, let’s look at the right side of this assignment. Based on previous knowledge we know that the splat operator on the right hand side will split, meaning that it will convert the array into a list of values like below:
```ruby
array = [2, 3, 4, 5]
a, *b, c = 1, 2, 3, 4, 5
```
Now that we’ve done that, let's look at the left hand side of the assignment. As per the rules that we learned earlier, we will allocate the first variable `a` to the first value `1`. We have the splat in the middle so let's leave that for last. We then allocate out the last variable to the last value, so `c` is assigned to `5`. Finally, we’ll focus on the splat operator which indicates that we should slurp up the rest of the values `[2, 3, 4]` to assign to `b`.
## Implicit and Explicit Splats
If we have an assignment containing just one variable on the left with a number of values on the right, it will slurp up all of the values into a new array.
```ruby
a = 1, 2, 3, 4
a => [1, 2, 3, 4]
```
This is equivalent to
```ruby
a* = 1, 2, 3, 4
a => [1, 2, 3, 4]
```
Notice that in the first example we didn’t need the asterisk, the value was just *implicitly spatted*. In some cases where the assignments are more straightforward, this is acceptable.
However, if you wanted to perform destructuring where there is more than one variable on the left you would need to explicitly splat the variable. You would also have noticed in some of the above sections that there are cases whereby an array will be listed alongside individual values, and hence you would need an explicit splat to break down the array into its component values.
## Keyword Arguments
In a rails app you’ll often come across a splat on argument methods, like `*args` below:
```ruby
def say_hello(name, *args)
puts "hello #{name}"
args.each do |arg|
puts "hello #{arg}"
end
end
say_hello("Goofy", "Donald Duck", "Fred Flinstone", "Pluto")
=> hello Goofy
=> hello Donald Duck
=> hello Fred Flinstone
=> hello Pluto
```
Abiding to our previous rules outlined, the splat operator on `*args` collects the rest of the parameters except the one assigned to `name`. It then converts those “rest” of the arguments to an array within the method, hence, allowing us to loop through the args.
In this manner, we don’t need to specify the number of arguments that we are providing to the method. Instead, we can deal with them as an array that we loop through.
The parameter with the splat operator is also optional, which means that if we omit these arguments to a method, Ruby will not complain about it.
```ruby
say_hello("Goofy", "Donald Duck", "Fred Flinstone", "Pluto")
=> hello Goofy
=> []
```
It is important to note that a method cannot have two parameters with a splat operator, and you can only splat the last parameter to a method.
Now that we’ve got a good foundation on how destructuring is used, let’s talk about when we would use destructuring.
## Use Cases
Destructuring can be used:
- When you do not want to specify the number of parameters that you have.
- When you want to make the parameter optional - a parameter with a splat operator is optional.
- When you’d like to convert a list of arguments to an array within the method and vice versa - when you want to convert an array into several arguments..
- You can use destructuring when programming in a functional, recursive manner whereby you can assign the first parameter to one variable and the rest of the variables can be assigned to another variable using a splat.
The scenarios above are only some instances where destructuring can be useful, let me know how you’ve used destructuring in the past.
![Cut a slice of cake gif](https://media.giphy.com/media/xUPGcCM0nd2A4sIuaY/giphy.gif)
Posted on August 3, 2022
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.