When to use keyword arguments aka named parameters in Ruby

saihgala picture saihgala · Feb 25, 2013 · Viewed 15.1k times · Source

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)

Answer

Davey picture Davey · Jan 28, 2015

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.