DEV Community

loading...

Ruby Keyword Arguments

Donald Dong
ใƒป2 min read

In Ruby 2, keyword arguments are essentially the same as a hash object at the end of the positional arguments.

Ruby 2.x:

def test(*args)
  p args
end
test(1, {y: 2}) # [1, {:y=>2}]
test(1, y: 2) # [1, {:y=>2}]
Enter fullscreen mode Exit fullscreen mode

Ruby 2.x:

def test2(hash={}, **kwargs)
  p [hash, kwargs]
end
test2({y: 2}) # [{}, {:y=>2}]
test2(y: 2) # [{}, {:y=>2}]
Enter fullscreen mode Exit fullscreen mode

Though I have passed in a hash, it's actually picked up by the kwargs.
This... is probably not something one would expect, right?


So, in Ruby 3, keyword arguments are completely separated from the normal arguments (learn more here).

Ruby 3.0.0:

def test2(hash={}, **kwargs)
  p [hash, kwargs]
end
test2({y: 2}) # [{:y=>2}, {}]
test2(y: 2) # [{}, {:y=>2}]
Enter fullscreen mode Exit fullscreen mode

If a method has explicit keyword arguments in Ruby 3, all the callers must explicitly pass in keyword arguments (or explicitly unpack a hash as the keyword args) in order to supply the keyword args.

Using this standard, one could write Ruby code that's compatible with both Ruby 2 and Ruby 3.

Caveat

Thereโ€™s a catch in writing Ruby 2 and Ruby 3 compatible code though:

Ruby 2.x:

def foo; end
a = []
b = {}
foo(*a, **b) # this is okay
send(:foo, *a, **b)  # this is not okay: ArgumentError (wrong number of arguments (given 1, expected 0))
Enter fullscreen mode Exit fullscreen mode

There is a bug in Ruby 2 that is causing issues when unpacking empty hashes for kwargs (fixed in Ruby 3). In some cases, weโ€™d have to conditionally unpack the kw hashes in Ruby 2 so that the code works with both Ruby versions (unpacking empty kw hashes causes errors sometimes). As a result, the actual code would look a bit ugly (with an if statement to unpack only if the kw hash is not empty), unfortunately ๐Ÿ˜….

Another option is to use https://github.com/ruby/ruby2_keywords but it's better to actually fix the keyword argument passing when possible.

Discussion (0)

Forem Open with the Forem app