Passing arguments in Ruby
One of the philosophical views behind Ruby is the Principle of flexibility - there are many ways to achieve the same thing. This is especially true when it comes to passing arguments to a method.
In this post, we will take a look on argument passing in Ruby and discuss pros and cons for each of the approaches.
Positional arguments
The most basic way to pass arguments. Positional arguments have some disadvantages such as Connascence of position. Each time we change the arguments list, we have to also change all of the method invocations throughout the code due to the imposed order of arguments.
We will discuss an alternative later.
Default arguments
Methods can have default values when using positional arguments. Arguments with default values should be always on the right when mixed with arguments that have no default values.
Unused method arguments
One naming convention that is worth mentioning. Let's look at the following example:
Wonder why _number_two
is prefixed with an underscore?
This is a common convention for positional arguments - we prefix with underscore method arguments that are not used in the method definition but are only present to keep the method arity consistent (the number of accepted arguments by a method).
A good practice is to keep the name of the variable and not just name it _
as this would impact the readability, especially when working on a project with a larger codebase.
Non-fixed number of arguments
We saw how to pass a fixed number of arguments. But what about passing a non-fixed number?
Consider this piece of code:
In situations like this one, my_method
can accept one or more arguments.
All, except the first one, are handled by *arguments
. They are just being stored into the array, referenced into the local variable arguments
.
This can be handy in some particular situations. On the other hand, it may be a symptom of a code smell.
kwargs
Keyword arguments are an alternative to positional arguments. KWargs are very similar to passing a hash as an argument. Ruby has a first-class support for KWargs.
Some historical facts:
- Required keyword arguments were added in Ruby 2.1
- Keyword arguments must have default values in Ruby 2.0
As mentioned, methods can accept hashes as an input.
This is the old way of managing keyword arguments but the drawback is that it requires logic for argument extraction from the given input. Luckily, kwargs solve such problems.
Default arguments
Just use the hash-like syntax in the argument list and decide whether you want default values or not.
The position of the arguments does not matter when using kwargs. Therefore, we do not need to worry about changing all of the method invocations when adding a new argument to our method.
Non-fixed number of arguments
KWargs are more strict than passing a plain hash and unknown attributes will raise an exception. This fosters traceability. The double splat operator (**
) could be used on the last argument to avoid this behaviour and use the additional arguments in some way:
options
references a hash that you can manage in a simmilar fashion as using the splat with positional arguments - it holds the rest of the keys that are not listed as kwargs.
Conclusion
- Passing many arguments to a method may be a symptom of a code smell.
- Prefer the usage of kwargs over positional arguments.
- Prefer kwargs over passing a hash as an argument.