I got an email asking for my opinion about when to use keyword arguments. I thought I’d expand my answer into a full article about method arguments so everyone can benefit!
Ruby is very flexible when it comes to method arguments…
…we have everything, from the standard required arguments to optional arguments & even keyword (named) arguments.
In this article, you are going to learn about the differences between all these argument types, and which ones to use depending on your situation.
Using the right kind of arguments will make your code easier to read & easier to work with.
Required arguments are what you get by default.
Here’ an example:
def write(file, data, mode) end write("cats.txt", "cats are cool!", "w")
If you don’t pass the exact number of arguments required you’ll get this familiar error message:
write("shopping_list.txt", "bacon") ArgumentError: wrong number of arguments (2 for 3)
This means that you gave the method
2 arguments, but it needs
You may want to make some of your arguments optional by providing a default value.
def write(file, data, mode = "w") end
Now you can call
write with 2 arguments, in which case
mode will equal the default value (
"w"), or you can pass in 3 arguments to override the default value & get different results.
This default value saves you some work when calling this method while still giving you the option to change it.
One of the downsides of required & default arguments is that they are order dependent. Meaning that you have to pass in the arguments in the same order.
If you pass them in the wrong order you’ll probably get unexpected results.
For example, in the
write method, you have to call it with the
file first, then the
data & finally the
def write(file, data, mode) end
Keyword arguments allow you to vary the order of the arguments.
Here’s an example:
def write(file:, data:, mode: "ascii") end
This allows you to call the method in a different order:
write(data: 123, file: "test.txt")
But more importantly, when you call the method you can clearly see the meaning of the arguments.
I don’t find myself using keyword arguments very often, but they can be useful when you want to add clarity to method calls.
Let’s say that we have a
You could write it like this:
class Point def initialize(x: , y:) @x, @y = x, y end end point = Point.new(x: 10, y: 20)
This way there is no possible confusion about which of the two numbers (10 & 20) correspond to the
x value or the
That’s one of your main goals when writing code, to avoid confusion & misunderstanding as much as possible. If using keyword arguments helps you do that then use them.
Think about this:
“Will adding keyword arguments make this easier to understand or will it add extra work & clutter to my code?”
Another thing about keyword arguments is that they are very explicit about the arguments you are missing.
point = Point.new # missing keywords: x, y
You can also combine keyword arguments with regular arguments. One strategy I’ve been observing on Ruby built-in methods is that new versions tend to add new, optional arguments, as keyword arguments.
Examples of this are the keyword arguments for
String#lines introduced in Ruby 2.4.
What if you want to take an unlimited amount of values?
Then you can use variable arguments:
def print_all(*args) end print_all(1, 2, 3, 4, 5)
This allows you to call the method with any number of arguments, including none. A variable argument is an array with all the values passed to it.
You can combine this with other types of arguments.
def print_all(title, *chapters) end
This will take the 1st argument as
title, and the rest as the
chapters array. Notice that a variable argument needs to be after all your required & optional arguments, and before any keyword arguments.
Here’s the valid order of arguments if you want to combine them & avoid a syntax error:
required -> optional -> variable -> keyword
Here’s a method that shows every possible argument type:
def testing(a, b = 1, *c, d: 1, **x) p a,b,c,d,x end testing('a', 'b', 'c', 'd', 'e', d: 2, x: 1)
**x is the same as variable arguments, but for keyword arguments. It will be a hash instead of an array.
In some rare occasions you may see this:
def print_all(*) end
This means that the method is accepting any arguments, but it’s not doing anything with them. It’s similar to using the underscore character (
_) inside a block to show which arguments you aren’t using.
A practical use for this could be in combination with the super keyword:
class Food def nutrition(vitamins, minerals) puts vitamins puts minerals end end class Bacon < Food def nutrition(*) super end end bacon = Bacon.new bacon.nutrition("B6", "Iron")
Now when Food’s
nutrition changes its argument list, you don’t have to change arguments in
You’ve learned about Ruby’s powerful method arguments & how to use them! Required arguments are a good start, then you can add flexibility with optional arguments & add clarity with keyword arguments.
Hope you found this useful & interesting!
Share this post on Twitter so more people can see it 🙂