Ruby : What is the *(asterix) in function param : *arg

The * is the splat operator. It expands an Array into a list of arguments, in this case a list of arguments to the Hash.[] method. (To be more precise, it expands any object that responds to to_ary/to_a, or to_a in Ruby 1.9.)

To illustrate, the following two statements are equal:

method_name arg1, arg2, arg3 
method_name *[arg1, arg2, arg3]
It can also be used in a different context, to catch all remaining method arguments in a method definition. In that case, it does not expand, but combine:
2.1.1 :001 > def display_sentence(occupation, age, *sentence)
2.1.1 :002?>   p "my occupation is #{occupation}"
2.1.1 :003?>   p "my age is #{age} years"
2.1.1 :004?>   p sentence.join(' ')
2.1.1 :005?> end
 => :display_sentence
2.1.1 :006 > display_sentence('Engineer', 25, 'My', 'name', 'is', 'Shiva' , 'Bhusal.', 'I', 'am', 'from', 'Nepal')
"my occupation is Engineer"
"my age is 25 years"
"My name is Shiva Bhusal. I am from Nepal"
 => "My name is Shiva Bhusal. I am from Nepal"
2.1.1 :007 >

The splat operator unpacks an array passed to a function so that each element is sent to the function as an individual parameter.

2.1.1 :001 > params = ['My', 'name', 'is', 'Shiva' , 'Bhusal']
 => ["My", "name", "is", "Shiva", "Bhusal"] 
2.1.1 :002 > def display_sentence(my, name, is, first_name, last_name)
2.1.1 :003?>    p [my, name, is, first_name, last_name].join(' ')
2.1.1 :004?> end
 => :display_sentence 

2.1.1 :005 > display_sentence(params)
ArgumentError: wrong number of arguments (1 for 5)

2.1.1 :006 > display_sentence(*params)
"My name is Shiva Bhusal"
 => "My name is Shiva Bhusal" 
2.1.1 :007 >

however if we have done this,

2.1.1 :007 > def display_sentence(*sentence)
2.1.1 :008?>    p sentence.join(' ')
2.1.1 :009?> end
 => :display_sentence 

2.1.1 :010 > display_sentence(params)
"My name is Shiva Bhusal"
 => "My name is Shiva Bhusal" 
2.1.1 :011 >

Splat for Wizards

Array De-structuring

First of all, lets quickly cover a few things you can do without splatting:

a,b = 1,2               # Assign 2 values at once
a,b = b,a               # Assign values in parallel
puts "#{a} and #{b}"
# 2 and 1

With the above samples in mind, let’s try some fancier stuff. You can use splats with multiple assignment to extract various elements from a list:

first, *list = [1,2,3,4]          # first= 1, list= [2,3,4]
*list, last  = [1,2,3,4]          # list= [1,2,3], last= 4
first, *center, last = [1,2,3,4]  # first= 1, center= [2,3], last=4
# Unquote a String (don't do this)
_, *unquoted, _ = '"quoted"'.split(//)
puts unquoted.join
# quoted

Array Coercion

If for some reason the previous examples seemed like great ideas to you, you’ll be thrilled to know that the splat can also be used to coerce values into arrays:

a = *"Hello"  #=> ["Hello"]
"Hello".to_a  #=> NoMethodError: undefined method `to_a' for "Hello":String
a = *(1..3)   #=> [1, 2, 3]
a = *[1,2,3]  #=> [1, 2, 3]

Array to Hash Conversion

The best use of splat! for invoking a infinite-arity functions I’ve ever seen is the recipe for converting an array to a hash. Suppose you have an array of pairs:

array = [[key_1, value_1], [key_2, value_2], ... [key_n, value_n]]

You would like to produce from it the hash: {key1 => value1 ... } You could inject down the array, everybody loves inject, but there is a better way:


Amazing right? This relies on the the fact that the Hash class implements the [] (brackets) operator and behaves thusly:

Hash[key1, value1, ...] = { key1 => value1, ... }

naked asterisk as parameter in method definition: def f(*)

We know what this means:

def f(*args)

But what does this mean and why would you want to use it? Can it appear with named parameters, too?

def f(*)

def f(*) has the same effect as def f(*args), except that it does not name the globbed argument array. You might use it if you want the function to accept any number of arguments but don’t actually need to refer to them within the function — for example, if you are overriding a method but calling super without passing an explicit argument list, which results in the original arguments being passed to super.



Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )


Connecting to %s