DEV Community

Ridhwana Khan
Ridhwana Khan

Posted on

Destructuring in Ruby

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 
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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:

a, b, c = 1, 2, 3, 4

a => 1 
b => 2 
c => 3 
Enter fullscreen mode Exit fullscreen mode

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:

a, b, *c = 1, 2, 3, 4

a => 1 
b => 2 
c => [3, 4]
Enter fullscreen mode Exit fullscreen mode

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.

a, *b, c = 1, 2, 3, 4

a => 1 
b => [2, 3] 
c => 4
Enter fullscreen mode Exit fullscreen mode

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?

*a, b, c = 1, 2, 3, 4
Enter fullscreen mode Exit fullscreen mode

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.

a, *b, c = [1, 2, 3, 4, 5]
a => 1
b => [2, 3, 4]
c => 5
Enter fullscreen mode Exit fullscreen mode

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.

list = [2, 3, 4]

a, b, c  = 1, *list 
Enter fullscreen mode Exit fullscreen mode

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:

a, b, c  = 1, 2, 3, 4
Enter fullscreen mode Exit fullscreen mode

and so the assignments happen as per usual:

a => 1
b => 2
c => 3
Enter fullscreen mode Exit fullscreen mode

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

array =  [2, 3, 4, 5]

a, *b, c = 1, *array
Enter fullscreen mode Exit fullscreen mode

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:

array =  [2, 3, 4, 5]

a, *b, c = 1, 2, 3, 4, 5 
Enter fullscreen mode Exit fullscreen mode

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.

a = 1, 2, 3, 4

a => [1, 2, 3, 4] 
Enter fullscreen mode Exit fullscreen mode

This is equivalent to

a* = 1, 2, 3, 4

a => [1, 2, 3, 4] 
Enter fullscreen mode Exit fullscreen mode

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:

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
Enter fullscreen mode Exit fullscreen mode

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.

say_hello("Goofy", "Donald Duck", "Fred Flinstone", "Pluto")

=> hello Goofy
=> []
Enter fullscreen mode Exit fullscreen mode

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

Oldest comments (1)

Collapse
 
faraazahmad profile image
Syed Faraaz Ahmad

Wait so the way positional arguments work in Ruby is also used for variable destructuring in a simple code block? Thats such an elegant language implementation!