Ruby's Double Splat Operator

Open up an IRB console and follow along with me.

It can be confusing

The double splat never ceases to confuse me:

# which of the following methods are correct?
# open an irb and try it out, if you don't know.

def ds_1(**hash) # correct?
	hash
end

def ds_2(hash**) # or is this correct?
	hash
end

# ds_1 is correct
# ds_2 is wrong

#_______________________

# Which one is correct?
h = {a: "a", b: "b"}

ds_1(h) # can I do this? 
ds_1(**h) # will this work?

# ds_1(h) will not work.
# ds_1(**h) will work

# Is it just me or it is slightly tricky?

The tricky part is that the double splat can be used both as an argument passed in, and also in a method definition.

def ds_3(**hash)	
	hash
end


h = {a: "a", b: "b"}

ds_3(a: "a")
# => {a: "a"}

ds_3(a: "a", b: "b")
# => {:a=>"a", :b=>"b"}
# what do you think will happen here?

ds_3(h) # What do you think will happen here?
# => irb):22:in `ds_3': wrong number of arguments (given 1, expected 0) (ArgumentError)

## Oops!
# How can we make it work?

ds_3(**h)
# => {:a=>"a", :b=>"b"}

Wait, so double splat can be used as a parameter in a method, and also as an argument passed into a method?

Yep.

**h essentially destructures a hash.

**h
# => <top (required)>': (irb):20: syntax error, unexpected **arg (SyntaxError)

# but it will work in a hash
{**h}
# => {:a=>"a", :b=>"b"}

Consider:

def ds_3(**hash) # This turns keyword arguments into a hash	
	hash
end

hash_1 = {:a=>"a", :b=>"b"}

ds_3(**hash_1) # and this turns a hash into key words

# But we can do interesting things:

def ds_4(a: , **hash)
	puts "a is #{a}, hash is: #{hash}"
end

ds_4(hash_1) # what do you expect?
# => `ds_4': wrong number of arguments (given 1, expected 0; required keyword: a) (ArgumentError)

ds_4(a: 1, hash_1)
# Nope. syntax error

ds_4(a: 1, b: 2)
# => a is 1, hash is: {:b=>2}

ds_4(a: 1, **hash_1) # what do you expect
# a is 1, hash is: {:b=>"b"}    or:
# a is a, hash is: {:b=>"b"}

# the answer is the latter.
ds_4(a: 1, **hash_1)
# => a is a, hash is: {:b=>"b"}

ds_4(a: 1, a: "a")
# => a is a, hash is: {}   (and you also have a duplicate key warning)
Written on December 6, 2024