Ruby Splat Operator ๐ŸŒŸ

Sami Birnbaum

The Ruby splat operator is confusing and here is why: it does two things that are the exact opposite of each other. Let me explainโ€ฆ

Destructuring

It destructures an array, which looks something like this:

x, y, z = *[1,2,3]

puts x 
# => 1

puts y 
# => 2

puts z 
# => 3

Constructing

But it can also be used to construct an array:

x = *123
# => [123]

If you think about this, it is doing two very different things.

One takes an array and removes the surrounding square brackets [].

*[123] becomes 123

The other takes a value and adds the surrounding square brackets [].

*123 becomes [123]

When does it destruct and when does it construct?

The only question we need to answer then is when does it destruct and when does it construct? ๐Ÿค”

If you use it when defining a method it will take any argument you give it and construct it into an array.

def describe_args(*args)
  puts args
  puts args.class
end

describe_args(1,2,3)
# 1
# 2
# 3
# Array

If you use it when passing arguments as an array to a method it will deconstruct the array into arguments.

def describe_first_arg(x,y,z)
  puts x
  puts x.class
end

describe_first_arg(*[1,2,3])
# 1
# Integer

Practical Application

Hopefully, we can now understand a class method you may have come across:

def self.perform(*args)
  new(*args).perform 
end

At first glance this looks strange and complex but using our newfound understanding of the splat operator we can understand what this is doing.

class SumTotal
  def self.perform(*args) # this splat operator will construct any arguments into an array
    new(*args).perform # this splat operator will deconstruct that array into arguments 
  end

  def initialize(x,y)
    @x = x
    @y = y
  end

  def perform
   puts @x + @y
  end
end

SumTotal.perform(5,5)
# => 10

SumTotal.perform(5,5)
# => 10
sum_total = SumTotal.new(5,5)
sum_total.perform
# => 10
class SumTotal
  def self.perform(*args)
    new(*args).perform
  end

  def initialize(x,y,z)
    @x = x
    @y = y
    @z = z
  end

  def perform
   puts @x + @y + @z
  end
end

SumTotal.perform(5,5,5)
# => 15

The initialize and perform method have changed but we can make those changes without having to worry about the self.perform class method.


Thank you to Starr Horne’s article Using splats to build up and tear apart arrays in Ruby, which helped to shape my understanding.