Recently I started using keyword arguments in my ruby work. They were fun at first, but I eventually became frustrated with their added complexity and inconsistencies with ordered and hash parameters.
1. Keyword arguments don’t convert into hashes
Hash arguments are really flexible. They can be modified and passed into other functions, as shown below.
1 2 3 4
Keyword arguments can’t do this. Instead, they need to be explicitly stated.
1 2 3 4
One solution to this is converting the named argument inputs into a hash, but this is surprisingly tricky. The best way to do this was suggested by Dennis on Stackoverflow.
1 2 3 4 5
Hashes can easily be converted to keyword arguments, so it’s strange that it’s so difficult to convert keyword arguments into hashes.
2. Keyword argument calls don’t use variable names
Keyword arguments can be quite non-dry from the context of the calling function.
1 2 3 4 5 6 7 8
We could use a hash to dry this up.
1 2 3 4 5 6 7 8 9 10 11
Of course, using a hash for this destroys some of the point of using named parameters. We need to make a things hash and the naming is longer than ideal.
Compare this to the following theoretical example.
1 2 3 4 5 6 7 8
The downside to this, of course, is that it would require one to use the keywords
computers as their variable names before these calls. However, this may be a really good thing. It would enforce more similar naming conventions throughout an application.
3. Implicit hash parameters are easy to get confused with keyword arguments
What do you expect this following code to produce?
1 2 3 4 5 6
The answer is:
b:89 was the first argument, ruby assumes that it represents the beginning of a hash parameter, so will take all key:value arguments and apply them to
a as a hash.
a has a default value it acts as would be originally expected.
1 2 3 4 5 6 7 8 9
4. It is difficult to make keyword arguments drop-in replacements for positional arguments
As one expands their use of keyword arguments, opportunities should arise to validate outputs before runtime. However, most methods don’t yet feature keyword arguments.
What if we want a method to accept either positional arguments or named arguments? A user could then call
make_sandwich(bread, cheese) or
make_sandwich(bread:bread, cheese:cheese)? This could be because
make_sandwich has been around before Ruby 2.0, but we want to use keyword arguments in the future of the codebase.
1 2 3 4 5 6 7
Or with delegation
1 2 3 4 5 6 7 8 9 10
These both are terrible. Perhaps there are more elegant solution, but there doesn’t seem to be something obvious, especially something standardized.
What does the future hold?
Keyword arguments are interesting, but their relationship with hashes and positional arguments is messy and a bit confusing. This may get cleaned up, but perhaps a better solution would be to do a complete rethink of parameters.
Ruby 3.0 may introduce static typing, with syntax like the following:
Hopefully this will not end up in four different kinds of arguments, but rather will be done in a large parameter consolidation If so, keyword arguments may only exist temporarily in the history of Ruby. They may be handy to use briefly in new ruby projects that support them, but I would advise against doing a large refactor to implement them. You’ll likely have to introduce more biolerplate than you expect to.