Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

When to use keyword arguments aka named parameters in Ruby

Ruby 2.0.0 supports keyword arguments (KA) and I wonder what the benefits/use-cases are of this feature in context of pure Ruby, especially when seen in light of the performance penalty due to the keyword matching that needs to be done every time a method with keyword arguments is called.

require 'benchmark'

def foo(a:1,b:2,c:3)
  [a,b,c]
end

def bar(a,b,c)
  [a,b,c]
end

number = 1000000
Benchmark.bm(4) do |bm|
  bm.report("foo") { number.times { foo(a:7,b:8,c:9)  } }
  bm.report("bar") { number.times { bar(7,8,9) } }
end

#           user     system      total        real
# foo    2.797000   0.032000   2.829000 (  2.906362)
# bar    0.234000   0.000000   0.234000 (  0.250010)
like image 836
saihgala Avatar asked Feb 25 '13 08:02

saihgala


People also ask

What are keyword arguments in Ruby?

What are keyword arguments? Keyword arguments are a feature in Ruby 2.0 and higher. They're an alternative to positional arguments, and are really similar (conceptually) to passing a hash to a function, but with better and more explicit errors.

Why do we use named parameters?

Named parameters provides us the relaxation to remember or to look up the order of parameters in the parameter lists of called methods. The parameter for each argument can be specified by parameter name. Using named parameters in C#, we can put any parameter in any sequence as long as the name is there.

How do you pass keyword arguments in Ruby?

So when you want to pass keyword arguments, you should always use foo(k: expr) or foo(**expr) . If you want to accept keyword arguments, in principle you should always use def foo(k: default) or def foo(k:) or def foo(**kwargs) .

What is a keyword parameter argument?

Keyword arguments (or named arguments) are values that, when passed into a function, are identifiable by specific parameter names. A keyword argument is preceded by a parameter and the assignment operator, = . Keyword arguments can be likened to dictionaries in that they map a value to a keyword.


1 Answers

Keyword arguments have a few distinct advantages no one has touched on.

First off you are not coupled to the order of the arguments. So in a case where you might have a nil argument occasionally it looks a lot cleaner:

def print_greeting(name, message = "Hello")
  puts "#{message}, #{name}"
end

print_greeting("John Connor", "Hasta la vista") 

If you use keyword arguments:

def print_greeting(message: "Hello", name:)
  puts "#{message}, #{name}"
end

print_greeting(message: "Hasta la vista", name: "John Connor") 

or even

print_greeting(name: "John Connor", message: "Goodbye")

It removes the need to have to remember the order of the arguments. However, the disadvantage is you have to remember the argument's name. This should be more or less intuitive, and arguably results in more carefully considered method signatures.

Another benefit to using keyword arguments is when you have a method that could require additional arguments in the future.

def create_person(name:, age:, height:)
  # make yourself some friends
end

What if your system requirements now need to know about a person's favorite candy bar, or if they are overweight (from consuming too many of their favorite candy bars). How could you use keyword args to do that? Simple:

def create_person(name:, age:, height:, favorite_candy:, overweight: true)
  # make yourself some fat friends
end

Before keyword arguments there was always the hash, but that led to a lot more boilerplate code to extract and assign variable. Boilerplate code == more typing == more potential typos == less times writing awesome ruby code.

def old_way(name, opts={})
  age    = opts[:age]
  height = opts[:height]
  # all the benefits as before, more arthritis and headaches  
end

If you are just setting up a method that takes one argument and will most likely never have a need to change:

def say_full_name(first_name, last_name)
  puts "#{first_name} #{last_name}"
end

Then keyword arguments should be avoided, since there is a small performance hit.

like image 65
Davey Avatar answered Jan 01 '23 20:01

Davey