April 14, 2020
A notable change has been announced for Ruby 3 for which deprecation warning has been added in Ruby 2.7. Ruby 2.7 deprecated automatic conversion of keyword arguments and positional arguments. This conversion will be completely removed in Ruby 3.
Ruby 2.7 NEWS has listed the spec of keyword arguments for Ruby 3.0. We will take the examples mentioned there and for each scenario we will look into how we can fix them in the existing codebase.
When method definition accepts keyword arguments as the last argument.
def sum(a: 0, b: 0)
a + b
end
Passing exact keyword arguments in a method call is acceptable, but in applications we usually pass a hash to a method call.
sum(a: 2, b: 4) # OK
sum({ a: 2, b: 4 }) # Warned
In this case, we can add a double splat operator to the hash to avoid deprecation warning.
sum(**{ a: 2, b: 4 }) # OK
When method call passes keyword arguments but does not pass enough required positional arguments.
If the number of positional arguments doesn't match with method definition, then keyword arguments passed in method call will be considered as the last positional argument to the method.
def sum(num, x: 0)
num.values.sum + x
end
sum(a: 2, b: 4) # Warned
sum(a: 2, b: 4, x: 6) # Warned
To avoid deprecation warning and for code to be compatible with Ruby 3, we should pass hash instead of keyword arguments in method call.
sum({ a: 2, b: 4 }) # OK
sum({ a: 2, b: 4}, x: 6) # OK
When a method accepts a hash and keyword arguments but method call passes only hash or keyword arguments.
If a method arguments are a mix of symbol keys and non-symbol keys, and the method definition accepts either one of them then Ruby splits the keyword arguments but also raises a warning.
def sum(num={}, x: 0)
num.values.sum + x
end
sum("x" => 2, x: 4) # Warned
sum(x: 2, "x" => 4) # Warned
To fix this warning, we should pass hash separately as defined in the method definition.
sum({ "x" => 4 }, x: 2) # OK
When an empty hash with double splat operator is passed to a method that doesn't accept keyword arguments.
Passing keyword arguments using double splat operator to a method that doesn't accept keyword argument will send empty hash similar to earlier version of Ruby but will raise a warning.
def sum(num)
num.values.sum
end
numbers = {}
sum(**numbers) # Warned
To avoid this warning, we should change method call to pass hash instead of using double splat operator.
numbers = {}
sum(numbers) # OK
In Ruby 2.6.0, support for non-symbol keys in method call was removed. It is added back in Ruby 2.7. When method accepts arbitrary keyword arguments using double splat operator then non-symbol keys can also be passed.
def sum(**num)
num.values.sum
end
sum("x" => 4, "y" => 3)
=> ArgumentError (wrong number of arguments (given 1, expected 0))
sum(x: 4, y: 3)
=> 7
sum("x" => 4, "y" => 3)
=> 7
sum(x: 4, y: 3)
=> 7
**nil
Ruby 2.7 added support for **nil
to explicitly mention if a method doesn't
accept any keyword arguments in method call.
def sum(a, b, **nil)
a + b
end
sum(2, 3, x: 4)
=> ArgumentError (no keywords accepted)
To suppress above deprecation warnings we can use
-W:no-deprecated option
.
In conclusion, Ruby 2.7 has worked big steps towards changing specification of keyword arguments which will be completely changed in Ruby 3.
For more information on discussion, code changes and official documentation, please head to Feature #14183 discussion, pull request and NEWS release.
If this blog was helpful, check out our full blog archive.